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

时间:2014-11-02 17:54:58

标签: 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"

如果我们切换B1B2

class A(B2, B1):
    pass

A().f()

我得到AttributeError: 'super' object has no attribute 'temp'

2 个答案:

答案 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?不,所以
  • 下一课fB1吗?是的!

然后调用B1.f,调用B2.temp(self),检查:

  • 班级fB2吗?是的!

它被调用,打印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?不,所以
  • 下一课fB2吗?不,所以
  • 下一课fB1吗?是的!

调用B1.f,调用object.temp(self),检查:

  • 班级fobject吗?否,
  • 没有超类,所以我们找不到属性。
  • 提升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

如果A2objecttemp()没有A1方法,那么下一个也是唯一一个类会引发错误。

如果B1 B2之后的temp()下一个班级{{1}},{{1}}方法有{{1}},则不会产生错误。