简体   繁体   English

关于 python 3.x MRO 和“super()”的问题

[英]question regarding python 3.x MRO and "super()"

This code shows error : AttributeError: 'super' object has no attribute 'method'此代码显示错误:AttributeError: 'super' object has no attribute 'method'

this same code does not shows error when "super.method()" is removed in class C. Why?当在 class C中删除“super.method()”时,同样的代码不会显示错误。为什么?

class A(object):
    def method(self):
        print("\n class A method")
        super().method()

class B(object):
    def method(self):
        print("\n class B method")
        super().method()

class C(object):
    def method(self):
        print("\n class C method")
        super().method()
        

class X(A, B):
    def method(self):
        print("\n class X method")
        super().method()

class Y(B, C):
    def method(self):
        print("\n class Y method")
        super().method()

class P(X, Y, C):
    def method(self):
        print("\n class P method")
        super().method()

p = P()
p.method()

print(P.mro())

I want to know, why this program is showing errors when "super().method" is included in class C, and why this same program is NOT SHOWING ERROR, when "super().method" is removed in class C?我想知道,为什么这个程序在 class C 中包含“super().method”时显示错误,为什么在 class C 中删除“super().method”时这个程序不显示错误?

This is not a bug, but a feature of working with multiple inheritance and super .这不是错误,而是使用多个 inheritance 和super的功能。 Let me answer your questions one by one:让我一一回答你的问题:

why this program is showing errors when "super().method" is included in class C?为什么这个程序在 class C 中包含“super().method”时显示错误?

The reason is that the base class object does not have a method called method .原因是基类 class object没有名为method的方法。 You will see the same exception when calling C().method() or simply object().method() .调用C().method()或简单地object().method()时,您会看到相同的异常。 So I guess this is quite expected.所以我想这是意料之中的。

why this same program is NOT SHOWING ERROR, when "super().method" is removed in class C?为什么同一个程序在 class C 中删除“super().method”时不显示错误?

This is the magic of python's method resolution order (MRO).这就是python的方法解析顺序(MRO)的神奇之处。 If you execute如果你执行

print(P.mro())

you should see你应该看到

[__main__.P,
 __main__.X,
 __main__.A,
 __main__.Y,
 __main__.B,
 __main__.C,
 object]

Here, you see that a super call will not call all parents of a class until the top of the inheritance tree and then take the next class. Instead, it will call them according to their "generation".在这里,你看到super调用不会调用一个 class 的所有父代,直到 inheritance 树的顶部,然后取下一个 class。相反,它会根据它们的“代”来调用它们。

Look at the following example:看下面的例子:

class Base:
    def method(self):
        print("Base")

class ParentA(Base):
    def method(self):
        print('Parent A')
        super().method()
        
class ParentB(Base):
    def method(self):
        print("Parent B")
        
class Child(ParentA, ParentB):
    def method(self):
        print("Child")
        super().method()

print(Child.mro())
Child().method()

Which will give you哪个会给你

[<class '__main__.Child'>, <class '__main__.ParentA'>, <class '__main__.ParentB'>, <class '__main__.Base'>, <class 'object'>]
Child
Parent A
Parent B

You do not see the line Base , because super in ParentA is ignored due to the presence of ParentB which shares the same base.您看不到Base行,因为ParentB中的super由于存在共享相同基数的ParentA而被忽略。

However, if you swap the inheritance, you will see the line Base printed.但是,如果您交换 inheritance,您将看到打印的Base行。 In short, follow the MRO, but if the last class in a generation does not call super, the chain stops.简而言之,遵循MRO,但如果一代中的最后一个class不调用super,则链停止。

I agree that this is not intuitive, but in practice this is rarely a problem, or if you have to think about the MRO to understand the code, it would be a good candidate for refactoring.我同意这不直观,但在实践中这很少成为问题,或者如果您必须考虑 MRO 来理解代码,这将是重构的一个很好的候选者。

To understand the MRO, I recommend to read https://en.wikipedia.org/wiki/C3_linearization or other related questions at SO.要了解 MRO,我建议阅读https://en.wikipedia.org/wiki/C3_linearization或 SO 上的其他相关问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM