问题:正确的使用超级方法(参数传递)
所以我一直在关注Python的超级有害,并去测试他的例子。
但是,示例1-3假定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
。
现在,很明显,奈特先生希望他的例子行得通,这是否在最新版本的Python中有所改变?我检查了2.6和2.7,但两者均失败。
那么解决这个问题的正确方法是什么?
回答 0
有时两个类可能有一些相同的参数名称。在这种情况下,您无法将键值对从中弹出**kwargs
或从中删除*args
。相反,您可以定义一个Base
不同于object
,吸收/忽略参数的类:
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)
Yield
MRO: ['E', 'C', 'A', 'D', 'B', 'Base', 'object']
E arg= 10
C arg= 10
A
D arg= 10
B
请注意,要使其正常工作,Base
必须是MRO中的倒数第二个类。
回答 1
如果您要继承很多东西(在这里就是这种情况),建议您使用传递所有参数**kwargs
,然后pop
在使用它们后立即传递它们(除非在上层类中需要它们)。
class First(object):
def __init__(self, *args, **kwargs):
self.first_arg = kwargs.pop('first_arg')
super(First, self).__init__(*args, **kwargs)
class Second(First):
def __init__(self, *args, **kwargs):
self.second_arg = kwargs.pop('second_arg')
super(Second, self).__init__(*args, **kwargs)
class Third(Second):
def __init__(self, *args, **kwargs):
self.third_arg = kwargs.pop('third_arg')
super(Third, self).__init__(*args, **kwargs)
这是解决这类问题的最简单方法。
third = Third(first_arg=1, second_arg=2, third_arg=3)
回答 2
正如Python在super()中所认为的super所解释的那样,一种方法是让类吃掉它所需的参数,然后传递其余的参数。因此,当调用链到达时object
,所有参数都被吃掉了,并且object.__init__
将在不带参数的情况下调用它(如预期的那样)。因此,您的代码应如下所示:
class A(object):
def __init__(self, *args, **kwargs):
print "A"
super(A, self).__init__(*args, **kwargs)
class B(object):
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__(*args, **kwargs)
class D(B):
def __init__(self, arg, *args, **kwargs):
print "D", "arg=",arg
super(D, self).__init__(*args, **kwargs)
class E(C,D):
def __init__(self, arg, *args, **kwargs):
print "E", "arg=",arg
super(E, self).__init__(*args, **kwargs)
print "MRO:", [x.__name__ for x in E.__mro__]
E(10, 20, 30)
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。