昨天在Python类的多重继承那里纠结了好久,在提问版块提了个问题探讨了探讨(链接)才完全搞明白,现在把类的特性整理下,供以后参考
正文
首先得说明的是,Python的类分为经典类 和 新式类
经典类是python2.2之前的东西,但是在2.7还在兼容,但是在3之后的版本就只承认新式类了
新式类在python2.2之后的版本中都可以使用
经典类和新式类的区别在于:
- 经典类是默认没有派生自某个基类的,而新式类是默认派生自
object
这个基类的:
1 2 3 4 5 6 |
# old style class A():pass # new style class A(obejct):pass |
2.经典类在类多重继承的时候是采用从左到右深度优先
原则匹配方法的..而新式类是采用C3算法
(不同于广度优先)进行匹配的
3.经典类是没有__MRO__
和instance.mro()
调用的,而新式类是有的.
为什么不用经典类,要更换到新式类
因为在经典类中的多重继承会有些问题…可能导致在继承树中的方法查询绕过后面的父类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class A(): def foo1(self): print "A" class B(A): def foo2(self): pass class C(A): def foo1(self): print "C" class D(B, C): pass d = D() d.foo1() |
按照经典类的查找顺序从左到右深度优先
的规则,在访问d.foo1()
的时候,D这个类是没有的..那么往上查找,先找到B,里面没有,深度优先,访问A,找到了foo1(),所以这时候调用的是A的foo1(),从而导致C重写的foo1()被绕过.
所以python引入了新式类的概念,每个基类都继承自object
并且,他的匹配规则也从深度优先
换到了C3
C3算法
C3算法是怎么做匹配的呢..在问答版块上面讨论之后,归结如下:
C3算法的一个核心是merge
.
在merge列表中,如果第一个序列mro的第一个类是出现在其它序列,并且也是第一个,或者不出现其它序列,那么这个类就会从这些序列中删除,并合到访问顺序列表中
比如:(引用问题中zhuangzebo的回答@zhuangzebo)
1 2 3 4 5 6 |
class A(O):pass class B(O):pass class C(O):pass class D(A,B):pass class E(C,D):pass |
首先需要知道 O(object)的mro
(method resolution order)列表是[O,]
那么接下来是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
mro(A) = [A, O] mro(B) = [B, O] mro(C) = [C, O] mro(D) = [D] + merge(mro(A), mro(B), [A, B]) = [D] + merge([A, O], [B, O], [A, B]) = [D, A] + merge([O], [B, O], [B]) = [D, A, B] + merge([O], [O]) = [D, A, B, O] mro(E) = [E] + merge(mro(C), mro(D), [C, D]) = [E] + merge([C, O], [D, A, B, O], [C, D]) = [E, C] + merge([O], [D, A, B, O], [D]) = [E, C, D] + merge([O], [A, B, O]) = [E, C, D, A, B] + span>C, D, A, B] + >
经典类是python2.2之前的东西,但是在2.7还在兼容,但是在3之后的版本就只承认新式类了 新式类在python2.2之后的版本中都可以使用 经典类和新式类的区别在于:
2.经典类在类多重继承的时候是采用 3.经典类是没有 为什么不用经典类,要更换到新式类因为在经典类中的多重继承会有些问题…可能导致在继承树中的方法查询绕过后面的父类:
按照经典类的查找顺序 所以python引入了新式类的概念,每个基类都继承自 C3算法C3算法是怎么做匹配的呢..在问答版块上面讨论之后,归结如下: C3算法的一个核心是
比如:(引用问题中zhuangzebo的回答@zhuangzebo)
首先需要知道 O(object)的
|