我正在尝试理解Python多重继承,我有点理解MRO,super()和在MI中传递参数,但是当我阅读下面的例子时,它让我很困惑。
class Contact:
all_contacts = []
def __init__(self, name=None, email=None, **kwargs):
super().__init__(**kwargs)
self.name = name
self.email = email
self.all_contacts.append(self)
class AddressHolder:
def __init__(self, street=None, city=None, state=None, code=None, **kwargs):
super().__init__(**kwargs)
self.street = street
self.city = city
self.state = state
self.code = code
class Friend(Contact, AddressHolder):
def __init__(self, phone='', **kwargs):
super().__init__(**kwargs)
self.phone = phone
现在我无法理解为什么在Contact和AddressHolder类中使用super()。我的意思是当我们从父类继承但是同时接触&时使用super()。 AddressHolder不是从任何其他类继承的。 (从技术上讲,它们是继承自object
)。这个例子让我对正确使用super()
答案 0 :(得分:9)
所有(新样式)类都具有线性化方法分辨率顺序(MRO)。根据继承树,实际计算MRO可能有点令人费解,但它通过relatively simple algorithm确定性。 super
获得MRO中下一个班级的委托人。在您的示例中,Friend
具有以下MRO:
Friend -> Contact -> AddressHolder -> object
如果你打电话给Friend
的方法,你将得到一个委托给Contact
方法的委托人。如果该方法未调用super
,则永远不会在AddressHolder
上调用方法。换句话说,super
只负责调用MRO中的下一个方法,而不是 ALL MRO中的其余方法。
这一切都很好,因为object
具有完全正常的__init__
方法(只要**kwargs
在此时为空)。不幸的是,如果您尝试解决某些自定义方法的调用链,则它不起作用。例如foo
。在这种情况下,您希望插入所有基类继承的基类。因为该类是所有类(或至少是基类)继承的基础。该类最终将在MRO结束时进行参数验证 1 :
class FooProvider:
def foo(self, **kwargs):
assert not kwargs # Make sure all kwargs have been stripped
class Bar(FooProvider):
def foo(self, x, **kwargs):
self.x = x
super().foo(**kwargs)
class Baz(FooProvider):
def foo(self, y, **kwargs):
self.y = y
super().foo(**kwargs)
class Qux(Bar, Baz):
def foo(self, z, **kwargs):
self.z = z
super().foo(**kwargs)
演示:
>>> q = Qux()
>>> q.foo(x=1, y=2, z=3)
>>> vars(q)
{'z': 3, 'y': 2, 'x': 1}
>>> q.foo(die='invalid')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: foo() missing 1 required positional argument: 'z'
>>>
>>> q.foo(x=1, y=2, z=3, die='invalid')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/google/home/mgilson/sandbox/super_.py", line 18, in foo
super().foo(**kwargs)
File "/usr/local/google/home/mgilson/sandbox/super_.py", line 8, in foo
super().foo(**kwargs)
File "/usr/local/google/home/mgilson/sandbox/super_.py", line 13, in foo
super().foo(**kwargs)
File "/usr/local/google/home/mgilson/sandbox/super_.py", line 3, in foo
assert not kwargs # Make sure all kwargs have been stripped
AssertionError
注意,你仍然可以使用这种方法使用默认参数,这样就不会在那里松动太多。
1 注意,这不是处理这个问题的唯一策略 - 在制作mixins等时还可以采取其他方法,但这是迄今为止最多的稳健的方法。