类Link
用于构建和操作链表:
class Link:
"""A linked list with a first element and the rest."""
empty = ()
def __init__(self, first, rest=empty):
assert rest is Link.empty or isinstance(rest, Link)
self.first = first
self.rest = rest
def __getitem__(self, i):
if i == 0:
return self.first
else:
return self.rest[i-1]
def __len__(self):
return 1 + len(self.rest)
def __repr__(self):
"""Return a string that would evaluate to self."""
if self.rest is Link.empty:
rest = ''
else:
rest = ', ' + repr(self.rest)
return 'Link({0}{1})'.format(self.first, rest)
通过模仿__repr__
我想实现__add__
函数:
def __add__(self, other):
if self is Link.empty:
return other
else:
return Link(self.first, add(self.rest, other))
然而它不起作用并且给我这样的错误(隐藏了实际的文件路径):
>>> lst = Link(3, Link(4, Link(5)))
>>> lst
Link(3, Link(4, Link(5)))
>>> lst + lst
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "PATH_TO_THE_FILE", line 31, in __add__
return Link(self.first, add(self.rest, other))
NameError: name 'add' is not defined
所以我将__add__
的最后一行更改为:
return Link(self.first, self.rest.__add__(other))
这次错误变成了:
TypeError: can only concatenate tuple (not "Link") to tuple
然后我删除了班级中的__add__
方法并尝试了另一种方式:
首先将以下函数添加到模块中:
def extend_link(s, t):
if s is Link.empty:
return t
else:
return Link(s.first, extend_link(s.rest, t))
并在终端:
>>> lst = Link(3, Link(4, Link(5)))
>>> Link.__add__ = extend_link
>>> lst + lst
Link(3, Link(4, Link(5, Link(3, Link(4, Link(5))))))
为什么Link.__add__ = extend_link
有效,但在课堂上覆盖__add__
并不是?
PS:示例来自here
答案 0 :(得分:0)
您遇到的第一个错误是由于add
不存在。
您在班级中覆盖__add__
,这与覆盖+
运算符相对应。因此,add(self.rest, other)
应该只是self.rest + other
。
+
运算符的工作原理是查找左成员的__add__
方法,如果存在则调用它。这就是self.rest.__add__(other)
同样有效的原因。但是,重新定义__add__
的原因是可以直接使用+
,因此永远不应使用此名称调用__add__
。
现在,你得到的第二个错误有点棘手。它清楚地表明您正在尝试添加一个Link
实例和一个未定义的tuple
实例。一些调查让我意识到,self.rest
一度等于empty
。但empty
定义为()
,tuple
。
对此最简单的解决方法是检查__add__
定义是否其中一个成员等于empty
,并返回正确的结果,没有调用{{ 1}}。这就是您在+
函数中所做的。
更好的解决方法是构建您的extend_link
,以使其成为empty
个实例。