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),它检查:
它被调用,打印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))。