1、python多继承存在的问题
一个子类可以继承多个父类,这样的设计为人们所诟病,主要是因为:
1、容易导致可恶的菱形问题 2、在人们的世界观中,继承是"is-a"的关系
但在实际开发需求中,一个类还是有继承多个类的需求的,比如以下交通工具:
民航飞机、直升飞机、轿车,这三者都是交通工具,所以可以定义一个Vehicle作为他们的父类,
但是前两者有飞行功能,而第三者没有,这就需要定义一个含有飞行功能的类让前两者继承。
为了解决多继承带来的可读性问题,python提供了一种规范机制——Mixins机制
2、Mixins机制
简单来说Mixins机制指的是子类混合(mixin)不同类的功能,而这些类采用统一的命名规范(例如Mixin后缀),以此标识这些类只是用来混合功能的,并不是用来标识子类的从属"is-a"关系的,所以Mixins机制本质仍是多继承,但同样遵守”is-a”关系,如下
class Vehicle: # 交通工具 pass class FlyableMixin: def fly(self): ''' 飞行功能相应的代码 ''' print("I am flying") class CivilAircraft(FlyableMixin, Vehicle): # 民航飞机 pass class Helicopter(FlyableMixin, Vehicle): # 直升飞机 pass class Car(Vehicle): # 汽车 pass # ps: 采用某种规范(如命名规范)来解决具体的问题是python惯用的套路
if hasattr(os, "fork"): class ForkingUDPServer(ForkingMixIn, UDPServer): pass class ForkingTCPServer(ForkingMixIn, TCPServer): pass class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass
使用Mixins机制的注意事项:
1、首先它必须表示某一种功能,而不是某个物品,python 对于mixin类的命名方式一般以 Mixin, able, ible 为后缀 2、然后,它不依赖于子类的实现 3、最后,子类即便没有继承这个Mixin类,也照样可以工作,就是缺少了某个功能。
3、重用父类方法的两种方式
(1)方式一:指名道姓的使用某一类的函数
>>> class Teacher(People): ... def __init__(self,name,sex,age,title): ... People.__init__(self,name,age,sex) #调用的是函数,因而需要传入self ... self.title=title ... def teach(self): ... print('%s is teaching' %self.name)
(2)方式二:super()
调用super()会得到一个特殊的对象,该对象专门用来引用父类的属性,且严格按照MRO规定的顺序向后查找
在Python2中super的使用需要完整地写成super(自己的类名,self) ,而在python3中可以简写为super()
>>> class Teacher(People): ... def __init__(self,name,sex,age,title): ... super().__init__(name,age,sex) #调用的是绑定方法,自动传入self ... self.title=title ... def teach(self): ... print('%s is teaching' %self.name)
区别:
方式一是跟继承没有关系的,而方式二的super()是依赖于继承的,并且即使没有直接继承关系,super()仍然会按照MRO继续往后查找
>>> #A没有继承B ... class A: ... def test(self): ... super().test() ... >>> class B: ... def test(self): ... print('from B') ... >>> class C(A,B): ... pass ... >>> C.mro() # 在代码层面A并不是B的子类,但从MRO列表来看,属性查找时,就是按照顺序C->A->B->object,B就相当于A的“父类” [<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>,<class ‘object'>] >>> obj=C() >>> obj.test() # 属性查找的发起者是类C的对象obj,所以中途发生的属性查找都是参照C.mro() from B