day---29 Mixins机制与重用父类功能的两种方式

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
 

猜你喜欢

转载自www.cnblogs.com/surpass123/p/12678684.html