old-style and new-style 区分问题的引出
Python刚入门者或者因为业务接触Python的同学们,大多从Python3入手(现在很多的规范都是基于3展开)。但是由于历史原因,很多老旧业务的服务还是基于Python2,这就会造成很多不理解2与3版本差异的同学莫名碰到一些问题,old-style and new-style就是面向对象编程时会遇到的一个问题。
问题描述
子类ElectricCar继承基类Car
基类 Car:
class Car:
def __init__(self, speed):
self.speed = speed
子类 ElectricCar:
class ElectricCar(Car):
def __init__(self, speed):
super(ElectricCa, self).__init__(speed)
在python3.x环境下,子类调用基类正常,但是在python2.x环境下,出现报错TypeError: super() argument 1 must be type, not classobj
问题分析
使用super调用基类,需要调用的基类是基于new-style class。在python3.x中不管基类的写法(隐式继承了object),默认任何类都是new-style class,所以在3.x环境中何种操作都不会引发错误。至于报错的内容,接下来介绍old-style和new-style差异的时候会提及。
old-style and new-style差异
在python最早的版本,old-style是用户的唯一选择,这种专制局面一直维持到2.1版本。old-style class存在两个不相关的概念:“type"和"class”,例如Car().__class__为Car所属的类,type(Car())为Car的固定type <type ‘instance’>,从这一点可以推测出old-style class唯一继承名为"instance"的type。2.2版本开始为了统一"type"和"class"的概念引入了new-style,自此这个困扰的问题终于得到解决。
回到开始的报错内容,此处通过实例解释:
新建new-style class Car1:
class Car1(object):
def __init__(self, speed):
self.speed = speed
>>> type(Car)
<type 'classobj'>
>>> type(Car1)
<type 'type'>
所以new-style class使用super()方法会报无法引用old-style class的错误
new-style相对old-style的一些重要变更
- 引入super()
使用super()可以隐式访问已经被重写的基类方法注意super()是new-style特有的,明确这一点能有效避免新、旧混用。 - MRO 变更
- 新增descriptors
参考链接 - 新增__slots__
解决办法
通过上面的介绍,已经有了一个解决办法。在这里给出两个解决办法:
- 统一基类的style
将基类规范为new-style
class Car(object):
def __init__(self, speed):
self.speed = speed
- 在子类中显式出继承的基类,同时固化继承的基类
class ElectricCar(Car):
def __init__(self, speed):
Car.__init__(self, speed)
总结
- 形成习惯,避免混用的情况
- 跟进python发展趋势使用new-style classes