python 的多继承
Mixin
多继承
- C++ 支持多继承,Java 舍弃了多继承
- Java 中,一个类可以实现多个接口,一个接口也可以继承多个接口,详细可参看其他文档
- 多继承可能会带来二义性,python 实现多继承,那就要解决二义性问题,深度优先或者广度优先
python 的多继承
Python 使用 MRO(method resolution order 方法解析顺序)解决基类搜索顺序问题,MRO 搜索算法采用 C3 算法(py2.3 之后),阻止二义性并解决了继承单调性,深度优先
class A:
pass
class B(A):
pass
class C(A):
pass
class D(B):
pass
class E(D,C): # 如果写成 class E(C,D),再观察mro,注意,这是C3算法的继承单调性
pass
print(E.mro())
----------------------
[<class '__main__.E'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
Mixin
抽象类和抽象方法
- 基类中只定义,不实现的方法称为抽象方法
- 只要包含抽象方法的类称为抽象类
# 例1:区别于java等语言的抽象类和抽象方法
# python中抽象类仍可实例化
# python中子类的抽象方法仍可不实现
class Document: # 抽象类
def __init__(self, content):
self.content = content
def print(self): # 抽象方法
raise NotImplementedError('未实现')
class Word(Document):
def print(self):
print(self.content,'in word') # 类中的print和全局内建的print是否冲突呢?
class Pdf(Document):
def print(self):
print(self.content,'in pdf')
w = Word('test print string')
w.print()
# d = Document('test document string') # 可实例化,但抽象类不推荐去实例化
# d.print() # 抛异常
装饰器给类增加功能
- 给类动态增加属性
- 在需要的地方动态增加,更加灵活
# 例2: 只给需要的子类增加功能
class Document:
def __init__(self, content):
self.content = content
# 为了给类动态增加属性/方法,在类外定义一个方法
def printable(cls):
def _print(self): # 注意函数命名和全局内建print,区别例1
print('{0} print in {1}'.format(self.content,self.__class__.__name__))
cls.print = _print # 给类动态增加print方法
return cls
@printable # Word = printable(Word) # return Word
class Word(Document):
pass
class Pdf(Document):
pass
w = Word('test word string')
w.print()
------------------------------
test word string print in Word
# 不改动原代码
# 例3:
class Document:
def __init__(self, content):
self.content = content
class Word(Document):
pass
class Pdf(Document):
pass
###################################################
def printable(cls):
def _print(self):
print('{0} print in {1}'.format(self.content,self.__class__.__name__))
cls.print = _print
return cls
@printable
class Note(Word):
pass
n = Note('test note string')
n.print()
print(Note.__dict__) # 通过装饰器动态增加属性,修改了当前类,dict中增加了print
----------------------------------
test note string print in Note
{'__module__': '__main__', '__doc__': None, 'print': <function printable.<locals>._print at 0x000001C776FCF2F0>}
Mixin
- Mixin 是通过多继承实现的
- Mixin 体现的是一种组合的设计模式
- 从设计模式的角度,多组合,少继承。也就是说,对于缺失的 A,B,C 功能,分别用 AMixin、BMixin、CMixin 来进行组合增强
- Mixin 类通常放在继承列表的第一个位置
例4:
class Document:
def __init__(self, content):
self.content = content
class Word(Document):
pass
class Pdf(Document):
pass
###################################################
class PrintableMixin(Word):
def print(self):
print('{0} print in {1}'.format(self.content,self.__class__.__name__))
class Note(PrintableMixin,Word):
pass
n = Note('test note string')
print(n.__class__.mro())
n.print() #print()方法按照MRO去查找,通过观察mro,通过多继承,加入mixin类,改变了mro,相当于增加了属性
print(Note.__dict__) # 通过mixin,未修改当前类
-------------------------------------------------------
[<class '__main__.Note'>, <class '__main__.PrintableMixin'>, <class '__main__.Word'>, <class '__main__.Document'>, <class 'object'>]
test note string print in Note
{'__module__': '__main__', '__doc__': None}
- Mixin 好处:Mixin 类是类,可以再次继承,对该 Mixin 类进行扩展
# 如:
class SuperPrintableMixin(PrintalbleMixin):
# 之前增强
print('之前增强')
super().print()
# 之后增强
print('之后增强')
Mixin 遵循的使用原则
这些需要遵循的原则不是非要这么做,如果不遵循也不会有语法上的错误,只是建议遵循
- Mixin 类不要显式的出现
__init__
初始化方法,即其中仅包含需要补充的功能函数 - Mixin 类不要独立工作,他是准备混入 (mix in) 到其他类中的部分功能实现
- Mixin 的父类也应是 Mixin 类
- Mixin 类通常放在继承列表的第一个位置,如上例中
class Note(PrintableMixin,Word):
参考
- magedu