Python 多重继承中基类的顺序和super()用法

Python 多重继承中基类的顺序和super()用法,python,python-3.x,multiple-inheritance,super,Python,Python 3.x,Multiple Inheritance,Super,你能帮我理解这两种情况的区别吗 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”对象没有属性“temp”Py

你能帮我理解这两种情况的区别吗

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”对象没有属性“temp”

Python使用调用的东西来决定基类的顺序:“方法解析顺序”。非正式地说,这基本上有两部分:

  • 路径必须是层次结构,不能从一个类向下到它的超类,即使是间接的。因此,不允许循环,
    issubclass(X,Y)和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'>]
因此调用
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(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")
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
    是否在类的
    对象上?不,
  • 没有超类,因此我们无法找到该属性
  • Raise
    AttributeError(“{!r}对象没有属性{!r}”。格式(实例,属性\名称))

在这两种情况下,区别仅在于类
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'>]
[,]

[,]
现在,当您调用
A1.f()
A2.f()
时,该属性在
B1
中找到,并且在那里您调用
super().temp()
,这意味着在
MRO
中找到下一个类时调用
temp()
(或者在未找到
temp
之前移动到它旁边的类,依此类推)

由于
A2
的下一个也是唯一一个类是
object
,它没有
temp()
方法,因此引发了一个错误


如果
A1
B1
之后的下一个类是
B2
,它有一个
temp()
方法,因此不会产生错误

什么让你困惑
B2
没有实现
f
,因此如果先在那里查找它(在第二种情况下),就找不到它。我猜OP不理解为什么类A的参数顺序在这里很重要,或者顺序有什么影响。
[<class '__main__.A2'>, <class '__main__.B2'>, <class '__main__.B1'>, <class 'object'>]