繁体   English   中英

Python和多重继承中的方法顺序

[英]Python and order of methods in multiple inheritance

在Python中,如果使用相同的方法定义两个类并且打算将这两个类作为父类,则:

class A(object):
     def hello(self):
         print "hello from class a" 

和:

class B(object):
     def hello(self):
         print "hello from class b"

当您定义子类并按顺序A和B添加两个父类时:

class C(A, B):
     def __init__(self):
         self.hello()

调用self.method()时使用的方法是属于A的方法,或继承列表中的第一个类:

>>> C()
hello from class a
<__main__.C object at 0x10571e9d0>

虽然在我的所有测试用例中似乎都是如此,但我无法在文档或在线中找到它在任何平台和语言实现中实际上是安全的。 任何人都可以确认可以安全地假设列表中的第一个继承类将始终是使用的方法(不管super().__ init __()调用等)或指向我确认这一点的官方文档?

谢谢,

是的,它保证如引入计算方法分辨率顺序的新算法( C3线性化 )的文档中所述。

不对其mro使用此算法的实现并不真正符合python语言(版本2.3+)。 AFAIK所有当前实现使用C3线性化。


C3线性化满足局部优先排序和单调性质。 本地优先级排序意味着类C(B1, ..., Bn)将在其mro中具有它们在继承列表中列出的顺序的基类Bi

通过一个例子可以更好地解释单调性:

>>> class A(object): pass
>>> class B(object): pass
>>> class C(object): pass
>>> class D(object): pass
>>> class E(object): pass
>>> class K1(A,B,C): pass
>>> class K2(D,B,E): pass
>>> class K3(D,A):   pass
>>> class Z(K1,K2,K3): pass

python2.2的旧mro( 不是单调),这些是上述类的线性化:

L[A] = A O
L[B] = B O
L[C] = C O
L[D] = D O
L[E] = E O
L[K1]= K1 A B C O
L[K2]= K2 D B E O
L[K3]= K3 D A O
L[Z] = Z K1 K3 A K2 D B C E O
# in current versions of python (2.3+):
# L[Z] = Z K1 K2 K3 D A B C E O

在这里你可以看到,在Z的线性化中, A类出现在D之前,而在K3的线性化中它出现 D 之后 单调性是线性化的特性,因此在继承时不存在这种交换。 如果类X在类的父类的所有线性化中都在类Y之前,则它也将在最终线性化中的类Y之前。

现在,如果我们考虑一个C(B1, ..., Bn)C(B1, ..., Bn) 通过局部优先顺序B1, ..., Bn将在C的线性化中以该顺序找到类B1, ..., Bn 通过单调性,我们无法在Bi本身之前找到Bi的子类。 由此得出, C的线性化(如果存在)必须以CB1开始。

请注意,在某些情况下,您无法计算线性化,并且python会抱怨,例如:

>>> class A(object):pass
... 
>>> class B(object, A): pass
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Cannot create a consistent method resolution
order (MRO) for bases object, A

但是,如果交换类,则可以线性化层次结构:

>>> class B(A, object): pass
... 
>>> B.mro()
[<class '__main__.B'>, <class '__main__.A'>, <class 'object'>]

如果父类没有共同的基础(显然除了object ),那么很明显C(B1, ..., Bn)的线性化将从B1的线性化开始(除了object ),然后将遵循线性化B2等,它将以Bn的线性化结束:

>>> class A(object): pass
... 
>>> class B(object): pass
... 
>>> class A1(A): pass
... 
>>> class A2(A1): pass
... 
>>> class B1(B): pass
... 
>>> class C(object): pass
... 
>>> class C1(C): pass
... 
>>> class C2(C1):pass
... 
>>> class C3(C2): pass
... 
>>> class D(A2, B1, C3): pass
... 
>>> D.mro()
[<class '__main__.D'>, <class '__main__.A2'>, <class '__main__.A1'>, <class '__main__.A'>, <class '__main__.B1'>, <class '__main__.B'>, <class '__main__.C3'>, <class '__main__.C2'>, <class '__main__.C1'>, <class '__main__.C'>, <class 'object'>]

当你在Bi之间有一些共同的子类时,事情开始变得奇怪,在这种情况下,python发现你期望的顺序不违反本地优先顺序和单调性,否则会引发错误。

以下是详细解释的方法解决顺序: http//www.python.org/download/releases/2.3/mro/

Python文档(词汇表)实际上指向了这一点。

根据我的经验,跨实现使用是安全的。 您可以使用__mro__mro()检查分辨率顺序。

class A(object):
    def hello(self):
        print 'hello from A'

class B(object):
    def hello(self):
        print 'hello from B'

class C(A, B):
    def __init__(self):
        self.hello()

>>> C()
hello from A
>>> print C.__mro__
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <type 'object'>)
>>> print C.mro()
[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <type 'object'>]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM