sat*_*esh 86 python method-resolution-order
在Python in a Nutshell(第2版)一书中,有一个示例使用
旧样式类来演示如何以经典分辨率顺序解析方法,
以及它与新顺序的不同之处.
我通过重写新样式的示例尝试了相同的示例,但结果与使用旧样式类获得的结果没有什么不同.我用来运行该示例的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__
Run Code Online (Sandbox Code Playgroud)
调用instance.amethod()
打印Base1
,但根据我对MRO的理解,新类型的输出应该是Base3
.通话Derived.__mro__
打印:
(<class '__main__.Derived'>, <class '__main__.Base2'>, <class '__main__.Base1'>, <class '__main__.Base3'>, <type 'object'>)
我不确定我对新样式类的MRO的理解是不正确的还是我做了一个我无法察觉的愚蠢错误.请帮助我更好地了解MRO.
Ale*_*lli 173
传统与新式类的解析顺序之间的关键区别在于,在"天真",深度优先的方法中,同一祖先类不止一次出现 - 例如,考虑"钻石继承"案例:
>>> class A: x = 'a'
...
>>> class B(A): pass
...
>>> class C(A): x = 'c'
...
>>> class D(B, C): pass
...
>>> D.x
'a'
Run Code Online (Sandbox Code Playgroud)
在这里,传统风格,分辨率顺序是D - B - A - C - A:所以当查找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'
>>>
Run Code Online (Sandbox Code Playgroud)
在这里,新式,顺序是:
>>> D.__mro__
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>,
<class '__main__.A'>, <type 'object'>)
Run Code Online (Sandbox Code Playgroud)
与A
被迫解析顺序进来只有一次,毕竟它的子类,从而使覆盖(即尺寸材料的的覆盖x
)实际上有效地工作.
这是应该避免使用旧式类的原因之一:使用"类似钻石"模式的多重继承对它们不起作用,而它与新风格一起使用.
Ben*_*Ben 22
Python的方法解析顺序实际上比仅仅理解菱形模式更复杂.要真正理解它,请看一下C3线性化.我发现在扩展跟踪订单的方法时使用print语句确实很有帮助.例如,您认为这种模式的输出是什么?(注意:'X'假设是两个交叉边,而不是节点,^表示调用super()的方法)
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
Run Code Online (Sandbox Code Playgroud)
你有ABDCEFG吗?
x = A()
x.m()
Run Code Online (Sandbox Code Playgroud)
经过大量的试验错误,我想出了一个非正式的图形理论解释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()
Run Code Online (Sandbox Code Playgroud)
你得到的结果是正确的.尝试更改Base3
to的基类Base1
并与经典类的相同层次结构进行比较:
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()
Run Code Online (Sandbox Code Playgroud)
现在输出:
Base3
Base1
Run Code Online (Sandbox Code Playgroud)
阅读此说明以获取更多信息.
归档时间: |
|
查看次数: |
51086 次 |
最近记录: |