因此,我遵循了Python的《超级被认为有害》,并去测试他的例子。
但是,示例1-3应该显示正确的调用方式,super当处理__init__期望使用不同参数的方法时,平坦化不起作用。
super
__init__
这是我得到的:
~ $ python example1-3.py MRO: ['E', 'C', 'A', 'D', 'B', 'object'] E arg= 10 C arg= 10 A D arg= 10 B Traceback (most recent call last): File "Download/example1-3.py", line 27, in <module> E(arg=10) File "Download/example1-3.py", line 24, in __init__ super(E, self).__init__(arg, *args, **kwargs) File "Download/example1-3.py", line 14, in __init__ super(C, self).__init__(arg, *args, **kwargs) File "Download/example1-3.py", line 4, in __init__ super(A, self).__init__(*args, **kwargs) File "Download/example1-3.py", line 19, in __init__ super(D, self).__init__(arg, *args, **kwargs) File "Download/example1-3.py", line 9, in __init__ super(B, self).__init__(*args, **kwargs) TypeError: object.__init__() takes no parameters
看来它object本身违反了文档中提到的最佳实践之一,即使用的方法super必须接受*args和**kwargs。
object
*args
**kwargs
现在,很明显,奈特先生希望他的例子能奏效,这在最近的Python版本中是否有所改变?我检查了2.6和2.7,但两者均失败。
那么解决这个问题的正确方法是什么?
有时两个类可能有一些相同的参数名称。在这种情况下,您无法将键值对从中弹出**kwargs或从中删除*args。相反,您可以定义一个Base不同于object,吸收/忽略参数的类:
Base
class Base(object): def __init__(self, *args, **kwargs): pass class A(Base): def __init__(self, *args, **kwargs): print "A" super(A, self).__init__(*args, **kwargs) class B(Base): def __init__(self, *args, **kwargs): print "B" super(B, self).__init__(*args, **kwargs) class C(A): def __init__(self, arg, *args, **kwargs): print "C","arg=",arg super(C, self).__init__(arg, *args, **kwargs) class D(B): def __init__(self, arg, *args, **kwargs): print "D", "arg=",arg super(D, self).__init__(arg, *args, **kwargs) class E(C,D): def __init__(self, arg, *args, **kwargs): print "E", "arg=",arg super(E, self).__init__(arg, *args, **kwargs) print "MRO:", [x.__name__ for x in E.__mro__] E(10)
产量
MRO: ['E', 'C', 'A', 'D', 'B', 'Base', 'object'] E arg= 10 C arg= 10 A D arg= 10 B
请注意,要使其正常工作,Base必须是MRO中的倒数第二个类。