假设我有一个多重继承场景:
class A(object): # code for A here class B(object): # code for B here class C(A, B): def __init__(self): # What's the right code to write here to ensure # A.__init__ and B.__init__ get called?
有两种典型的编写C方法__init__:
C
__init__
ParentClass.__init__(self)
super(DerivedClass, self).__init__()
但是,无论哪种情况,如果父类(A和B)不遵循相同的约定,那么代码将无法正常工作(有些可能会被遗漏,或者被多次调用)。
A
B
那么正确的方法是什么?说“只要保持一致,遵循其中一个”很容易,但如果A或B来自第三方库,那该怎么办?有没有一种方法可以确保所有父类构造函数都被调用(并且以正确的顺序,并且只调用一次)?
编辑:看看我的意思,如果我这样做:
class A(object): def __init__(self): print("Entering A") super(A, self).__init__() print("Leaving A") class B(object): def __init__(self): print("Entering B") super(B, self).__init__() print("Leaving B") class C(A, B): def __init__(self): print("Entering C") A.__init__(self) B.__init__(self) print("Leaving C")
然后我得到:
Entering C Entering A Entering B Leaving B Leaving A Entering B Leaving B Leaving C
请注意,Binit 被调用了两次。如果我这样做:
class A(object): def __init__(self): print("Entering A") print("Leaving A") class B(object): def __init__(self): print("Entering B") super(B, self).__init__() print("Leaving B") class C(A, B): def __init__(self): print("Entering C") super(C, self).__init__() print("Leaving C")
Entering C Entering A Leaving A Leaving C
请注意,B的 init 永远不会被调用。因此,除非我知道/控制我继承自的类的 init(A和B),否则我无法为正在编写的类做出安全的选择(C)。
为了正确处理多重继承场景中的初始化,尤其是在处理无法控制或假设方法行为的第三方库时__init__,您应该使用super()并确保层次结构中的所有类super()也使用。
super()
这里的关键是方法解析顺序 (MRO),Python 使用它来确定__init__方法的调用顺序。通过使用super(),Python 可以遵循 MRO,并__init__仅以正确的顺序调用每个类的方法一次。
下面是一个如何正确初始化类的示例:
class A(object): def __init__(self, *args, **kwargs): print("Entering A") super(A, self).__init__(*args, **kwargs) print("Leaving A") class B(object): def __init__(self, *args, **kwargs): print("Entering B") super(B, self).__init__(*args, **kwargs) print("Leaving B") class C(A, B): def __init__(self, *args, **kwargs): print("Entering C") super(C, self).__init__(*args, **kwargs) print("Leaving C") # Test the classes c = C()
运行此代码时,您应该得到以下输出:
Entering C Entering A Entering B Leaving B Leaving A Leaving C
以下是具体发生情况:
C.__init__
super(C, self).__init__
A.__init__
super(A, self).__init__
B.__init__
super(B, self).__init__
object.__init__
这样,所有__init__方法都只会以正确的顺序调用一次。使用super()可确保遵守 MRO,并避免多次初始化或错过初始化的问题。