![](/img/trans.png)
[英]How does multiple inheritance work with the super() and different __init__() arguments?
[英]How does Python pass __init__ parameters with multiple inheritance
我有以下代码,显示了经典的菱形图案:
class A:
def __init__( self, x ):
print( "A:" + x )
class B( A ):
def __init__( self, x ):
print( "B:" + x )
super().__init__( "b" )
class C( A ):
def __init__( self, x ):
print( "C:" + x )
super().__init__( "c" )
class D( B, C ):
def __init__( self ):
super().__init__( "d" )
d = D()
输出为:
B:d
C:b
A:c
B:d
是有道理的,因为D
源自B
A:c
我几乎得到了,尽管我同样可以看到A:b
。 C:b
位没有意义: C
不是从B
派生的。 有人可以解释吗?
问题如这个不幸的是没有提到的参数。
Python使用C3线性化算法来建立方法的解析顺序,这与super
委托的顺序相同。
基本上,该算法会为每个包含该类的类及其继承的每个类以及所涉及的类所继承的所有类保留列表。 然后,它通过逐个获取未被任何未经检查的类继承的类来构造类的排序,直到到达根object
为止。 下面,为了简洁起见,我将O
用作object
:
L(O) = [O]
L(A) = [A] + merge(L(O), [O]) = [A, O]
L(B) = [B] + merge(L(A), [A]) = [B] + merge([A, O], [A]) = [B, A] + merge([O])
= [B, A, O]
L(C) = [C] + merge(L(A), [A]) = [C] + merge([A, O], [A]) = [C, A] + merge([O])
= [C, A, O]
L(D) = [D] + merge(L(B), L(C), [B, C]) = [D] + merge([B, A, O], [C, A, O], [B, C])
= [D, B] + merge([A, O], [C, A, O], [C]) = [D, B, C] + merge([A, O], [A, O])
= [D, B, C, A, O]
Python中的类是动态组成的-包括继承。
C:b
输出并不表示B
神奇地继承自C
如果您实例化B
或C
,那么任何人都不知道对方。
>>> B('root')
B:root
A:b
但是, D
确实知道B
和C
:
class D(B,C):
...
有很多可用的技术 。 但是,工作原理基本上分为两部分:
B
在C
之前。 B
和C
基类必须都遵循。 对于类D
,这意味着基类解析为B->C->A
! C
已经潜入B
和A
之间-但仅适用于D
级,而不是B
级。
请注意,实际上还涉及另一个类:默认情况下,所有类都从object
派生。
>>> D.__mro__
(__main__.D, __main__.B, __main__.C, __main__.A, object)
您已经写了A
知道没有任何基础可以接受其参数。 但是, B
和C
都不能假定这一点。 他们都期望从A
对象派生。 子类化确实意味着B
和C
也是有效的A
对象,但是!
B
和 C
都在B
和 C
之前是有效的,因为这两个都是A
子类。 B->C->A->object
不会破坏B
期望其超类为A
类型。
对于所有其他组合,最后以C
开头(无效)或object
开头(无效)。 那排除了深度优先分辨率B->A->object->C
并复制了B->A->object->C->A->object
。
此方法解析顺序对启用mixins很有用:依赖其他类的类定义如何解析方法。
有一个很好的示例 ,说明字典访问记录器如何接受dict
和OrderedDict
。
# basic Logger working on ``dict``
class LoggingDict(dict):
def __setitem__(self, key, value):
logging.info('Settingto %r' % (key, value))
super().__setitem__(key, value)
# mixin of different ``dict`` subclass
class LoggingOD(LoggingDict, collections.OrderedDict):
pass
您始终可以检查任何类应具有的方法解析顺序:
>>> D.mro()
[__main__.D, __main__.B, __main__.C, __main__.A, object]
如您所见,如果每个人都在做正确的事情(即调用super),那么MRO将是第一父级,第二父级,第一父级的父级,依此类推...
您可以先考虑深度,然后从左至右查找顺序,尽管自python 2.3起算法发生了变化,但结果通常是相同的。
在这种情况下,B和C具有相同的父A,而A不调用super
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.