Python如何传递具有多重继承的__init__参数
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
. 派生的
有人可以解释一下吗?
诸如此类的问题this可惜没有提到参数
您始终可以检查任何 class 应该具有的方法解析顺序:
>>> D.mro()
[__main__.D, __main__.B, __main__.C, __main__.A, object]
如您所见,如果每个人都在做正确的事情(即调用 super),则 MRO 将是第一个父级、第二个父级、第一个父级的父级等等...
你可以先考虑深度,然后从左到右找到顺序,尽管自从 python 2.3 以来算法发生了变化,但结果是 usually 相同。
在这种情况下,B 和 C 有相同的父 A 并且 A 没有调用 super
Python uses the C3 linearization algorithm to establish the method resolution order, which is the same order that super
delegates in.
Basically, the algorithm keeps lists for every class containing that class and every class it inherits from, for all classes that the class in question inherits from. It then constructs an ordering of classes by taking classes that aren't inherited by any unexamined classes one by one, until it reaches the root, object
. Below, I use O
for object
for brevity:
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]
ClassPython 中的元素是动态组合的 - 包括继承。
C:b
输出并不意味着 B
神奇地继承自 C
。如果您实例化 B
或 C
,none 知道另一个。
>>> B('root')
B:root
A:b
然而,D
知道 B
和 C
:
class D(B,C):
...
这里有很多 technicalities 可用。但是,其工作原理基本上分为两部分:
- Direct Base Classes 按它们出现的顺序解析。
B
在 C
. 之前
- 递归基 Classes 被解析为不重复。
B
和 C
的基数 Class 必须跟在两者之后。
对于 class D
,这意味着基础 classes 解析为 B->C->A
! C
已经潜入 B
和 A
之间 - 但只针对 class D
,而不针对 class B
.
请注意,实际上还涉及 另一个 class:默认情况下,所有 class 派生自 object
。
>>> D.__mro__
(__main__.D, __main__.B, __main__.C, __main__.A, object)
你已经写了 A
知道没有基数来获取它的参数。但是,B
和 C
都不能假设这一点。他们都希望派生自 A
对象。 Subclassing 确实意味着 B
和 C
都是有效的 A
-对象,但是!
B
和C
都有效先于B
和 C
,因为这两个是A
的子class。 B->C->A->object
不会破坏 B
期望它的超 class 类型为 A
.
对于所有其他组合,最终结果是 C
前面没有任何内容(无效)或 object
前面有内容(无效)。这排除了深度优先分辨率 B->A->object->C
和重复 B->A->object->C->A->object
.
此方法解析顺序可用于启用 mixins: class依赖于其他 classes 来定义方法解析方式的 es。
有一个 nice example 用于字典访问的记录器如何接受 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
我有这段代码,显示了经典的菱形图案:
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
. 派生的
有人可以解释一下吗?
诸如此类的问题this可惜没有提到参数
您始终可以检查任何 class 应该具有的方法解析顺序:
>>> D.mro()
[__main__.D, __main__.B, __main__.C, __main__.A, object]
如您所见,如果每个人都在做正确的事情(即调用 super),则 MRO 将是第一个父级、第二个父级、第一个父级的父级等等...
你可以先考虑深度,然后从左到右找到顺序,尽管自从 python 2.3 以来算法发生了变化,但结果是 usually 相同。
在这种情况下,B 和 C 有相同的父 A 并且 A 没有调用 super
Python uses the C3 linearization algorithm to establish the method resolution order, which is the same order that super
delegates in.
Basically, the algorithm keeps lists for every class containing that class and every class it inherits from, for all classes that the class in question inherits from. It then constructs an ordering of classes by taking classes that aren't inherited by any unexamined classes one by one, until it reaches the root, object
. Below, I use O
for object
for brevity:
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]
ClassPython 中的元素是动态组合的 - 包括继承。
C:b
输出并不意味着 B
神奇地继承自 C
。如果您实例化 B
或 C
,none 知道另一个。
>>> B('root')
B:root
A:b
然而,D
知道 B
和 C
:
class D(B,C):
...
这里有很多 technicalities 可用。但是,其工作原理基本上分为两部分:
- Direct Base Classes 按它们出现的顺序解析。
B
在C
. 之前
- 递归基 Classes 被解析为不重复。
B
和C
的基数 Class 必须跟在两者之后。
对于 class D
,这意味着基础 classes 解析为 B->C->A
! C
已经潜入 B
和 A
之间 - 但只针对 class D
,而不针对 class B
.
请注意,实际上还涉及 另一个 class:默认情况下,所有 class 派生自 object
。
>>> D.__mro__
(__main__.D, __main__.B, __main__.C, __main__.A, object)
你已经写了 A
知道没有基数来获取它的参数。但是,B
和 C
都不能假设这一点。他们都希望派生自 A
对象。 Subclassing 确实意味着 B
和 C
都是有效的 A
-对象,但是!
B
和C
都有效先于B
和 C
,因为这两个是A
的子class。 B->C->A->object
不会破坏 B
期望它的超 class 类型为 A
.
对于所有其他组合,最终结果是 C
前面没有任何内容(无效)或 object
前面有内容(无效)。这排除了深度优先分辨率 B->A->object->C
和重复 B->A->object->C->A->object
.
此方法解析顺序可用于启用 mixins: class依赖于其他 classes 来定义方法解析方式的 es。
有一个 nice example 用于字典访问的记录器如何接受 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