假设我有一个多重继承的场景:
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__:
(老式)ParentClass.__init__(自我)
(new -style) super(DerivedClass, self).__init__()
然而,在任何一种情况下,如果父类(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
注意B的init被调用了两次。如果我这样做:
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从未被调用。因此,似乎除非我知道/控制从(A和B)继承的类的初始化,否则我无法为我正在编写的类(C)做出安全的选择。
下面是我如何在Python 3中使用super()实现多重继承
class A:
def __init__(self, a, b, **kwargs):
print("Class A initiallised")
self.a = a
self.b = b
super().__init__(**kwargs)
print("Class A initiallisation done")
def __str__(self):
return f"{self.a} and {self.b}"
def display_a(self):
return f"{self.a} and {self.b}"
class C:
def __init__(self, c, d, **kwargs):
print("Class C initiallised")
self.c = c
self.d = d
super().__init__(**kwargs)
print("class c initiallisation done")
def __str__(self):
return f"{self.c} and {self.d}"
def display_c(self):
return f"{self.c} and {self.d}"
class D(A,C):
def __init__(self, e, **kwargs):
print("Class D initiallised")
super().__init__(**kwargs)
self.e = e
print("Class D initiallisation done")
def __str__(self):
return f"{self.e} is e,{self.b} is b,{self.a} is a,{self.d} is d,{self.c} is c"
if __name__ == "__main__":
d = D(a=12, b=13, c=14, d=15, e=16)
print(d)
d.display_c()
d.display_a()
下面是我如何在Python 3中使用super()实现多重继承
class A:
def __init__(self, a, b, **kwargs):
print("Class A initiallised")
self.a = a
self.b = b
super().__init__(**kwargs)
print("Class A initiallisation done")
def __str__(self):
return f"{self.a} and {self.b}"
def display_a(self):
return f"{self.a} and {self.b}"
class C:
def __init__(self, c, d, **kwargs):
print("Class C initiallised")
self.c = c
self.d = d
super().__init__(**kwargs)
print("class c initiallisation done")
def __str__(self):
return f"{self.c} and {self.d}"
def display_c(self):
return f"{self.c} and {self.d}"
class D(A,C):
def __init__(self, e, **kwargs):
print("Class D initiallised")
super().__init__(**kwargs)
self.e = e
print("Class D initiallisation done")
def __str__(self):
return f"{self.e} is e,{self.b} is b,{self.a} is a,{self.d} is d,{self.c} is c"
if __name__ == "__main__":
d = D(a=12, b=13, c=14, d=15, e=16)
print(d)
d.display_c()
d.display_a()
这两种方法都很有效。使用super()的方法为子类带来了更大的灵活性。
在直接调用方法中,C.__init__可以同时调用A.__init__和B.__init__。
当使用super()时,类需要设计为合作多重继承,其中C调用super,它调用A的代码,后者也将调用super,后者调用B的代码。有关使用super可以做什么,请参阅http://rhettinger.wordpress.com/2011/05/26/super-considered-super。
[稍后编辑的回答问题]
所以除非我知道/控制类的初始化,否则我
我不能对我所在的班级做出安全的选择
写作(C)。
参考的文章展示了如何通过在a和b周围添加包装器类来处理这种情况。在“如何合并非合作类”一节中有一个设计好的示例。
有人可能希望多重继承更简单,让你毫不费力地组合Car和Airplane类来获得FlyingCar,但现实是,单独设计的组件通常需要适配器或包装器,然后才能像我们希望的那样无缝地组合在一起:
另一个想法是:如果你对使用多重继承的组合功能不满意,你可以使用组合来完全控制在什么情况下调用哪些方法。