这是从Learning Python第4版中提取的。它的功能是使用list子类设置。但我不明白第5行list.__init__([])
,请帮忙。即使我注释掉这行代码,代码也能正常工作。为什么?
### file: setsubclass.py
class Set(list):
def __init__(self, value = []): # Constructor
list.__init__([]) # Customizes list
self.concat(value) # Copies mutable defaults
def intersect(self, other): # other is any sequence
res = [] # self is the subject
for x in self:
if x in other: # Pick common items
res.append(x)
return Set(res) # Return a new Set
def union(self, other): # other is any sequence
res = Set(self) # Copy me and my list
res.concat(other)
return res
def concat(self, value): # value: list, Set . . .
for x in value: # Removes duplicates
if not x in self:
self.append(x)
def __and__(self, other): return self.intersect(other)
def __or__(self, other): return self.union(other)
def __repr__(self): return 'Set:' + list.__repr__(self)
if __name__ == '__main__':
x = Set([1,3,5,7])
y = Set([2,1,4,5,6])
print(x, y, len(x))
print(x.intersect(y), y.union(x))
print(x & y, x | y)
x.reverse(); print(x)
x
答案 0 :(得分:6)
书中的代码包含错误。我已经向O'Reilly的书籍提交了一份勘误表,您可以在this page(作者982)上阅读作者的回复。这是他回应的一小部分:
这个代码行显然已经出现在第二版(2003年 - 10年前)的书中,并且直到现在还没有被成千上万的读者注意到
第list.__init__([])
行错过了一个参数,并且将其注释掉没有任何区别,只是稍微加快了你的程序速度。这是更正的行:
list.__init__(self, [])
当直接在类对象上调用非静态方法或类方法的方法时,必须显式提供通常隐式的第一个参数self
。如果这条线被这样纠正,那么它将遵循Antonis在他的回答中谈到的良好做法。纠正这一行的另一种方法是使用super
,这又会隐含self
参数。
super(Set, self).__init__([])
本书中的代码提供了一个不同的空列表([]
)作为self
参数,这会导致 列表被初始化再一次,它很快就被垃圾收集了。换句话说,整行都是死代码。
要验证原始行没有效果很简单:暂时将[]
中的list.__init__([])
更改为非空列表,并观察生成的Set
实例不包含这些元素。然后插入self
作为第一个参数,并观察列表中的项目现在已添加到Set
实例。
答案 1 :(得分:4)
你的意思是这条线?
list.__init__([])
当您覆盖任何类型的__init__
方法时,总是调用继承的__init__
方法是一种很好的做法;也就是说,基类的__init__
方法。这样,您可以执行父类的初始化,并添加特定于子类的初始化代码。
即使您确信父母的__init__
什么都不做,也应该遵循这种做法,以确保与未来版本的兼容性。
更新:正如Lauritz在另一个答案中解释的那样,
行 list.__init__([])
错了。请参阅他的答案和其他答案。
答案 2 :(得分:3)
你的意思是list.__init__([])
?
它从子类初始化程序调用基本初始值设定项。您的子类已将替换基类初始值设定项及其自己的。
在这种情况下,注释掉的情况恰好起作用,因为未绑定的初始值设定项是使用空列表而不是self
调用的,因此是无操作。这很可能是代表作者的错误。
但是,通常确保基类在子类化时运行其初始化代码是一个好主意。这样,基类方法依赖的所有内部数据结构都已正确设置。
答案 3 :(得分:1)
这一行就像在Set类中创建一个__init__
构造函数一样,它调用它的基类构造函数。
您可能已经看过这个:
class Set(list):
...
def __init__(self, *args, **kwargs):
super(Set, self).__init__(args, kwargs)
# do something additional here