在多重继承中调用超类方法
我有以下代码:
class A:
pass
class B(A):
def foo(self, a):
if a:
return 'B'
return super(B, self).foo(a)
class C:
def foo(self, a):
return 'C'
class D(B, C):
def foo(self, a):
return super().foo(a)
d = D()
print(d.foo(0))
当我基于MRO调用d.foo(0)
时,它首先调用B
类的foo
方法,在其中,如果条件错误,它将返回super(B, self).foo(0)
,但类A
没有foo方法而且我期望这个错误:
When I call d.foo(0)
based on MRO it first calls the foo
method of B
class and inside that, if the condition is wrong and it will return super(B, self).foo(0)
but class A
has no foo method and I expect this error:
AttributeError: 'super' object has no attribute 'foo'
,但它从类C
返回'C'
.为什么?
but it returns 'C'
from class C
. Why?
super()
在MRO中搜索具有该属性的下一类; A
不实现它并不重要,因为仍在考虑C
.
super()
searches the MRO for the next class that has the attribute; that A
doesn't implement it doesn't matter as C
is still considered.
对于D
,MRO为D
,B
,A
,C
:
For D
, the MRO is D
, B
, A
, C
:
>>> D.__mro__
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.A'>, <class '__main__.C'>, <class 'object'>)
因此D
中的super().foo
将找到B.foo
,并且从B.foo
中跳过A
并找到了C.foo
;您可以从交互式解释器中对此进行测试:
so super().foo
in D
will find B.foo
, and from B.foo
, A
is skipped and C.foo
is found; you can test this yourself from the interactive interpreter:
>>> super(D, d).foo
<bound method B.foo of <__main__.D object at 0x1079edb38>>
>>> super(B, d).foo
<bound method C.foo of <__main__.D object at 0x1079edb38>>
这是属性搜索算法的Python实现的样子:
This is what a Python implementation of the attribute search algorithm would look like:
def find_attribute(type_, obj, name):
starttype = type(obj)
mro = iter(starttype.__mro__)
# skip past the start type in the MRO
for tp in mro:
if tp == type_:
break
# Search for the attribute on the remainder of the MRO
for tp in mro:
attrs = vars(tp)
if name in attrs:
res = attrs[name]
# if it is a descriptor object, bind it
descr = getattr(type(res), '__get__', None)
if descr is not None:
res = descr(
res,
None if obj is starttype else obj,
starttype)
return res
其中,type_
是super()
的第一个参数(方法在其上定义的类),obj
是实例(此处为type(d)
),而name
是您要查找的属性
where type_
is the first argument to super()
(the class the method is defined on), obj
is the instance (so type(d)
here), and name
is the attribute you are looking for.