Python的新式类和经典类
问题
在Python中定义类时,我们经常看到两种写法:
class PersonOne: name = "person one" class PersonTwo(object): name = "person two"
也就是说在Python中,继承object 与不继承object的写法有什么区别?
在Python2.X中,第一种写法称之为经典类,第二种写法称之为新式类。Python2.2之前只能支持第一种写法,在Python2.2到Python2.7,两种写法都可以,但是不同写法定义出来的类是不一样的;在Python3.X中两种写法都可以,而且定义出来的类是完全一样的,都是新式类,可以理解为和Java一样,Python3.0之后Object已经作为所有类的基类,因此是否显示指明已经不重要。因此,如果你是使用Python3.X的版本,完全可以无视这个问题,怎么写都行;但是如果不是就需要搞清楚区别了。
使用新式类和经典类的区别
个人理解,两种定义核心的区别就是定义类的MRO是不同的,在多重继承中,MRO直接决定了方法的调用顺序,因此会产生很大的影响。
经典类的MRO
经典类的MRO的生成时基于深度优先遍历算法的,以下面的继承关系为例,生成的MRO为:[D,B,A,C],因此,在调用test方法时,按照此顺序查找必然先找到A中的test方法,但是这其实是不太不合理的。class A: def test(self): print('in a test') class B(A): pass class C(A): def test(self): print('in c test') class D(B, C): pass if __name__ == '__main__': d = D() d.test()
- 新式类的MRO
在新式类中,MRO的生成时基于C3算法的,关于C3算法计算过程参见链接,核心就是Merge函数的计算过程,有的文章中直接说是广度优先其实并不准确。此处生成的类D的MRO为[D,B,C,A],那么,按照这个顺序调用test方法自然找到的是C中的test。
扩展
super的调用关系
在Python3中,我们经常使用到super方法,在单继承中没有什么疑问,直接调用super方法自然是访问其唯一的父类。但是再多继承中,又是如何决定调用哪一个父类的呢?这个还是和MRO有关。
准确来说,super方法的调用方式为super(ClassName, self).func(),那么此处的func方法就是属于MRO中ClassName下一个类。如果确实没有参数,即super().func(),等价于super(MRO中的第一个类, self).func()
还是以上面的继承关系为例,重写类D的__init__()方法,第一个super调用的是B,第二个是C。class D(B, C): def __init__(self): print("C") super().__init__() super(B, self).__init__()