类B
和C
从类A
继承。类 D
继承自 B
和 C
:
class A:
def __init__(self):
print('A')
class B(A):
def __init__(self):
A.__init__(self)
print('B')
class C(A):
def __init__(self):
A.__init__(self)
print('C')
class D(B, C):
def __init__(self):
B.__init__(self)
C.__init__(self)
print('D')
d = D()
这将输出:
A
B
A
C
D
有没有办法避免对A
构造函数的双重调用?
注意:在我的现实世界中,来自 B
和 C
的__init__
方法没有相同的签名,因此使用 super() 不是一种选择(据我了解......
干杯!
如果您知道A
将在多个基类中使用,则可以让它自行检测双重初始化。
class A:
def __init__(self):
if hasattr(self, '_initialized'):
return
print('A')
self._initialized = true
这绝对是应该使用super的情况。可以使用 *args
和 **kwargs
来控制参数在每个级别调度的方式。请务必注意,类声明 of D
中基类的顺序控制着超级搜索类查找下一个方法的顺序。因此,它还将控制使用位置参数的顺序。
例如。
class A:
def __init__(self, a, *, caller):
print("A.__init__(a={!r}) called by {}".format(a, caller))
class B(A):
def __init__(self, b, *args, caller, **kwargs):
super().__init__(caller="B", *args, **kwargs )
print("B.__init__(b={!r}) called by {}".format(b, caller))
class C(A):
def __init__(self, c, *args, caller, **kwargs):
super().__init__(caller="C", *args, **kwargs)
print("C.__init__(c={!r}) called by {}".format(c, caller))
class D(B, C):
def __init__(self, d, *args, **kwargs):
super().__init__(caller="D", *args, **kwargs)
print("D.__init__(d={!r}) called by {}".format(d, "user"))
try:
print("too many arguments")
D(a=1, b=2, c=3, d=4, e=5)
except TypeError as e:
print(e)
try:
print("too few arguments")
D(a=1, c=3, d=4)
except TypeError as e:
print(e)
print("using keyword args")
D(a=1, b=2, c=3, d=4)
print("using positional args")
D(4, 2, 3, 1) # as B comes before C, B's argument must come before C's
print("using a mix of positional and keyword args")
D(4, 2, a=1, c=3)
其输出为:
too many arguments
__init__() got an unexpected keyword argument 'e'
too few arguments
__init__() missing 1 required positional argument: 'b'
using keyword args
A.__init__(a=1) called by C
C.__init__(c=3) called by B
B.__init__(b=2) called by D
D.__init__(d=4) called by user
using positional args
A.__init__(a=1) called by C
C.__init__(c=3) called by B
B.__init__(b=2) called by D
D.__init__(d=4) called by user
using a mix of positional and keyword args
A.__init__(a=1) called by C
C.__init__(c=3) called by B
B.__init__(b=2) called by D
D.__init__(d=4) called by user
如果不确定搜索基类的顺序,请使用 D.mro()
。 mro
代表 方法解析顺序。它返回将搜索属性(在我们的例子中为 __init__
)的类列表。
>>> print(D.mro())
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>,
<class 'object'>]