你能帮我理解这两种情况之间的区别吗?
class B1:
def f(self):
super().temp()
class B2:
def temp(self):
print("B2")
class A(B1, B2):
pass
A().f()
打印"B2"
。
如果我们切换B1
和B2
:
class A(B2, B1):
pass
A().f()
我得到AttributeError: 'super' object has no attribute 'temp'
答案 0 :(得分:2)
Python使用名为C3 linearization的东西来决定基类的顺序:"方法解析顺序" 。当非正式地陈述时,这基本上有两个部分:
路径必须层次结构必须永远不会从类到其超类,甚至是间接的。因此,不允许循环,issubclass(X, Y) and issubclass(Y, Z)
暗示issubclass(X, Z)
。
上述规则未强制执行的顺序按最超级类的步数(较低的步数表示链中的较早)和然后的顺序排序类列表中的类(列表中的早期表示链中的早期版本)。
这里的层次结构是:
A
/ \
/ \
B1 B2 # Possibly switched
\ /
\ /
object
在第一种情况下,C3线性化后的顺序是
super super super
A → B1 → B2 → object
我们可以找到:
A.mro()
#>>> [<class 'A'>, <class 'B1'>, <class 'B2'>, <class 'object'>]
因此super()
调用将解析为:
class A(B1, B2):
pass
class B1:
def f(self):
# super() proxies the next link in the chain,
# which is B2. It implicitly passes self along.
B2.temp(self)
class B2:
def temp(self):
print("B2")
所以调用A().f()
尝试:
f
吗?不,所以f
A
?不,所以f
是B1
吗?是的!然后调用B1.f
,调用B2.temp(self)
,检查:
f
是B2
吗?是的!它被调用,打印B2
在第二种情况下,我们有
super super super
A → B2 → B1 → object
所以解决了
因此super()
调用将解析为:
class A(B2, B2):
pass
class B2:
def temp(self):
print("B2")
class B1:
def f(self):
# super() proxies the next link in the chain,
# which is B2. It implicitly passes self along.
object.temp(self)
f
吗?不,所以f
A
?不,所以f
是B2
吗?不,所以f
是B1
吗?是的!调用B1.f
,调用object.temp(self)
,检查:
f
是object
吗?否,AttributeError("{!r} object has no attribute {!r}".format(instance, attribute_name))
。答案 1 :(得分:0)
在两种情况下,差异只是类A
的MRO中的类的顺序:
class A1(B1, B2):
pass
class A2(B2, B1):
pass
print(A1.mro())
print(A2.mro())
返回:
[<class '__main__.A1'>, <class '__main__.B1'>, <class '__main__.B2'>, <class 'object'>]
和
[<class '__main__.A2'>, <class '__main__.B2'>, <class '__main__.B1'>, <class 'object'>]
现在,当您致电A1.f()
或A2.F()
时,B1
中会找到该属性,并在那里拨打super().temp()
,这意味着在下一次呼叫temp()
找到的课程(或者在找不到temp
之前继续上课,等等......)MRO
。
如果A2
为object
且temp()
没有A1
方法,那么下一个也是唯一一个类会引发错误。
如果B1
B2
之后的temp()
下一个班级{{1}},{{1}}方法有{{1}},则不会产生错误。