在书里 Python 简述(第二版) 有一个例子使用
旧式类演示如何以经典解析顺序解析方法,以及
与新订单有何不同?

我通过以新样式重写示例来尝试相同的示例,但结果与旧样式类获得的结果没有什么不同。我用来运行示例的 python 版本是 2.5.2. 下面是示例:

class Base1(object):  
    def amethod(self): print "Base1"  

class Base2(Base1):  
    pass

class Base3(object):  
    def amethod(self): print "Base3"

class Derived(Base2,Base3):  
    pass

instance = Derived()  
instance.amethod()  
print Derived.__mro__  

电话 instance.amethod() 印刷 Base1, ,但根据我对新风格类 MRO 的理解,输出应该是 Base3. 。电话 Derived.__mro__ 印刷:

(<class '__main__.Derived'>, <class '__main__.Base2'>, <class '__main__.Base1'>, <class '__main__.Base3'>, <type 'object'>)

我不确定我对新样式类的 MRO 的理解是否不正确,或者我犯了一个我无法检测到的愚蠢错误。请帮助我更好地理解 MRO。

有帮助吗?

解决方案

对于传统VS新式的类分辨率秩序之间的关键区别来当同一个祖先类中发生比“天真”,深度优先的方式再一次 - 例如,考虑一个“菱形继承”的情况:

>>> class A: x = 'a'
... 
>>> class B(A): pass
... 
>>> class C(A): x = 'c'
... 
>>> class D(B, C): pass
... 
>>> D.x
'a'

这里,传统型的,分辨率顺序是d - B - 甲 - C - 答:所以仰视DX时,A是在分辨率为了解决它,从而隐藏的定义C.虽然第一基:

>>> class A(object): x = 'a'
... 
>>> class B(A): pass
... 
>>> class C(A): x = 'c'
... 
>>> class D(B, C): pass
... 
>>> D.x
'c'
>>> 

这里,新的风格,顺序是:

>>> D.__mro__
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, 
    <class '__main__.A'>, <type 'object'>)

A被迫解析顺序进来只有一次,毕竟它的子类,以便覆盖(即,构件x的C'S倍率)实际上合理工作。

这是老式类应避免的原因之一:多重继承与“钻石般”的模式只是不与他们有效地工作,同时与新的风格确实

其他提示

Python的方法解析顺序实际上比只是理解菱形图案更加复杂。要的真正的理解,看看 C3线性。我发现它确实有助于使用打印报表时,延长的方法来跟踪订单。例如,您怎么看这种模式的输出会是什么? (注:“X”是假设是两个交叉的边缘,而不是一个节点和^意味着调用super方法(i))

class G():
    def m(self):
        print("G")

class F(G):
    def m(self):
        print("F")
        super().m()

class E(G):
    def m(self):
        print("E")
        super().m()

class D(G):
    def m(self):
        print("D")
        super().m()

class C(E):
    def m(self):
        print("C")
        super().m()

class B(D, E, F):
    def m(self):
        print("B")
        super().m()

class A(B, C):
    def m(self):
        print("A")
        super().m()


#      A^
#     / \
#    B^  C^
#   /| X
# D^ E^ F^
#  \ | /
#    G

你得到A B d C ^ E F G

x = A()
x.m()

在很多的尝试错误的,我想出了C3线性的非正式图论的解释如下:(有人请让我知道,如果这是错误的)

考虑这个例子:

class I(G):
    def m(self):
        print("I")
        super().m()

class H():
    def m(self):
        print("H")

class G(H):
    def m(self):
        print("G")
        super().m()

class F(H):
    def m(self):
        print("F")
        super().m()

class E(H):
    def m(self):
        print("E")
        super().m()

class D(F):
    def m(self):
        print("D")
        super().m()

class C(E, F, G):
    def m(self):
        print("C")
        super().m()

class B():
    def m(self):
        print("B")
        super().m()

class A(B, C, D):
    def m(self):
        print("A")
        super().m()

# Algorithm:

# 1. Build an inheritance graph such that the children point at the parents (you'll have to imagine the arrows are there) and
#    keeping the correct left to right order. (I've marked methods that call super with ^)

#          A^
#       /  |  \
#     /    |    \
#   B^     C^    D^  I^
#        / | \  /   /
#       /  |  X    /   
#      /   |/  \  /     
#    E^    F^   G^
#     \    |    /
#       \  |  / 
#          H
# (In this example, A is a child of B, so imagine an edge going FROM A TO B)

# 2. Remove all classes that aren't eventually inherited by A

#          A^
#       /  |  \
#     /    |    \
#   B^     C^    D^
#        / | \  /  
#       /  |  X    
#      /   |/  \ 
#    E^    F^   G^
#     \    |    /
#       \  |  / 
#          H

# 3. For each level of the graph from bottom to top
#       For each node in the level from right to left
#           Remove all of the edges coming into the node except for the right-most one
#           Remove all of the edges going out of the node except for the left-most one

# Level {H}
#
#          A^
#       /  |  \
#     /    |    \
#   B^     C^    D^
#        / | \  /  
#       /  |  X    
#      /   |/  \ 
#    E^    F^   G^
#               |
#               |
#               H

# Level {G F E}
#
#         A^
#       / |  \
#     /   |    \
#   B^    C^   D^
#         | \ /  
#         |  X    
#         | | \
#         E^F^ G^
#              |
#              |
#              H

# Level {D C B}
#
#      A^
#     /| \
#    / |  \
#   B^ C^ D^
#      |  |  
#      |  |    
#      |  |  
#      E^ F^ G^
#            |
#            |
#            H

# Level {A}
#
#   A^
#   |
#   |
#   B^  C^  D^
#       |   |
#       |   |
#       |   |
#       E^  F^  G^
#               |
#               |
#               H

# The resolution order can now be determined by reading from top to bottom, left to right.  A B C E D F G H

x = A()
x.m()

你得到的结果是正确的。尝试改变基类Base3Base1并用经典类相同的层次结构比较:

class Base1(object):
    def amethod(self): print "Base1"

class Base2(Base1):
    pass

class Base3(Base1):
    def amethod(self): print "Base3"

class Derived(Base2,Base3):
    pass

instance = Derived()
instance.amethod()


class Base1:
    def amethod(self): print "Base1"

class Base2(Base1):
    pass

class Base3(Base1):
    def amethod(self): print "Base3"

class Derived(Base2,Base3):
    pass

instance = Derived()
instance.amethod()

现在它输出:

Base3
Base1

读取这个解释获得更多的信息。

您看到这种行为是因为方法解析是深度优先,而不是广度优先。Dervied 的继承看起来像

         Base2 -> Base1
        /
Derived - Base3

所以 instance.amethod()

  1. 检查Base2,没有找到方法。
  2. 看到 Base2 继承自 Base1,并检查 Base1。Base1 有一个 amethod, ,所以它被调用。

这体现在 Derived.__mro__. 。简单地迭代一遍 Derived.__mro__ 当您找到正在寻找的方法时停止。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top