Python-面向对象之多继承
多继承
一个类继承自多个类就是多继承,它将具有多个类的属性型和方法。
多继承的弊端
多继承 很好的模拟了世界,因为事物是单一继承,但是舍弃简单,必然引起复杂性,带来了冲突。
如同一个孩子继承了父母双方的特性,那么到底是眼睛更像父亲还是母亲呢?孩子究竟像谁多一点呢?
多继承的实现会导致设计的复杂度增加,所以有些高级编程语言直接舍去了多继承。
C++支持多继承,Java舍弃了多继承。
多继承可能带来二义性,例如,猫和狗都是继承自动物类,现在如果一个类多继承了猫和狗类,猫和狗都有shout方法,子类究竟继承谁的shout呢?
解决方案:
实现多继承的语言,要解决二义性,深度优先和广度优先。
Python多继承实现
class ClassName(基类1,基类2[,......]) 语句块

左图是多继承(菱形继承),右图是单一继承。
多继承带来路径选择问题,究竟继承哪个父类的特征呢?
Python使用了MRO(method resolution order 方法解析顺序)解决基类的搜索顺序问题。

多继承的缺点
当类很多且继承复杂的情况下,继承路径太多,很难说清楚什么样的继承路径,Python语法是允许多继承,但Python代码是解释器执行,只有执行到的时候才知道发现错误,团队协作开发,如果引入多继承,那代码很可能失控。
不管编程语言是否支持多继承,都应该避免多继承,Python的面向对象,我们看到了太灵活了,太开放了,所以需要团队守规矩。
MIXIN
类有一下继承关系

文档Document类是其他所有文档类的抽象基类,Word,PDF类是Document的子类。
需求:为Document子类提供打印功能
使用单继承实现
class Document: def __init__(self,content): self.content = content class Word(Document): pass class Pdf(Document): pass class PrintWord(Word): def __init__(self,content): self.content = content def print(self): print(self.content) pw = PrintWord("test print word") pw.print() print(PrintWord.__dict__.items()) print(PrintWord.mro()) #输出 test print word dict_items([('__module__', '__main__'), ('__init__', <function PrintWord.__init__ at 0x000002203B81F048>), ('print', <function PrintWord.print at 0x000002203B81F0D0>), ('__doc__', None)]) [<class '__main__.PrintWord'>, <class '__main__.Word'>, <class '__main__.Document'>,<class 'object'>]
上诉方法看似不错,如果需要还要提供其他的能力,如何继承?
例如,如果该类用于网络传输,还应该具备序列化的能力,在类上就应该实现序列化。
可序列化还可能分为使用pickle、json、messagepack等。
这个时候发现,为了增加一种能力,就需要增加一次继承,类可能太多了,继承的方式不是很好。
可提供的功能太多,A类需要某几种功能,B类需要某几种功能,他们需要的是多个功能的自由组合,继承实现很繁琐。
使用装饰器实现
用一个装饰器增强一个类,把功能给类加上去,哪个类需要就给哪个类添加,装饰它。
def printable(cls): def _print(self): print(self.content,'装饰器') cls.print = _print return cls class Document: def __init__(self,content): self.content = content @printable class Word(Document): pass @printable class Pdf(Document): pass class PrintWord(Word): pass class PrintPdf(Pdf): pass pw = PrintWord("test print word") pw.print() print(PrintWord.__dict__.items()) print(PrintWord.mro()) pd = PrintPdf("print Pdf") pd.print() print(PrintPdf.__dict__.items()) print(PrintWord.mro()) test print word 装饰器 dict_items([('__module__', '__main__'), ('__doc__', None)]) [<class '__main__.PrintWord'>, <class '__main__.Word'>, <class '__main__.Document'>, <class 'object'>] print Pdf 装饰器 dict_items([('__module__', '__main__'), ('__doc__', None)]) [<class '__main__.PrintWord'>, <class '__main__.Word'>, <class '__main__.Document'>, <class 'object'>]
优点:
简单方便,在需要的地方动态增加,直接使用装饰器。
可以为类灵活的增加功能。
Mixin
class Document: def __init__(self,content): self.content = content class Word(Document): pass class Pdf(Document): pass class PrintableMixin: def print(self): print(self.content,'Mixin') class PrintableWord(PrintableMixin,Word): pass print(PrintableWord.mro()) print(PrintableWord.__dict__) pw = PrintableWord("test word print") pw.print() def Printable(cls): def _print(self): print(self.content,'装饰器') cls.print = _print return cls @Printable class PrintPdf(Pdf): pass pd = PrintPdf("test pdf print") pd.print() print(PrintPdf.mro()) print(PrintPdf.__dict__) #输出 [<class '__main__.PrintableWord'>, <class '__main__.PrintableMixin'>, <class '__main__.Word'>, <class '__main__.Document'>, <class 'object'>] {'__module__': '__main__', '__doc__': None} test word print Mixin test pdf print 装饰器 [<class '__main__.PrintPdf'>, <class '__main__.Pdf'>, <class '__main__.Document'>, <class 'object'>] {'__module__': '__main__', '__doc__': None, 'print': <function Printable.<locals>._print at 0x0000012A825300D0>}
Mixin就是其他类混合进来,同时带来了类的属性和方法。
这里看来Mixin类和装饰器效果一样,也没有什么特别的地方,但是Mixin是类,就可以继承。
class Document: def __init__(self,content): self.content = content class Word(Document): pass class Pdf(Document): pass class PrintableMixin: def print(self): print(self.content,'Mixin') class PrintableWord(PrintableMixin,Word): pass print(PrintableWord.mro()) print(PrintableWord.__dict__) pw = PrintableWord("test word print") pw.print() class SuperPrintableMixin(PrintableMixin): def print(self): print("~" * 30) super().print() print("~" * 30) class SuperPrintablePdf(SuperPrintableMixin,Pdf): pass supper = SuperPrintablePdf("supper print pdf") supper.print() #输出 [<class '__main__.PrintableWord'>, <class '__main__.PrintableMixin'>, <class '__main__.Word'>, <class '__main__.Document'>, <class 'object'>] {'__module__': '__main__', '__doc__': None} test word print Mixin ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ supper print pdf Mixin ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Mixin类
Mixin本质上是多继承实现的,Mixin体现是一种组合的设计模型。
在面向对象的设计中,一个复杂的类,往往需要很多功能,而这些功能有来自不同的类提供,这就需要很多类组合在一起,
从设计的模式来讲,多组合,少继承。
Mixin类的使用原则
Mixin类中不应该显式的出现__init__初始化方法
Mixin类通常补鞥呢独立工作,因为它是准备混入别的类中的部分功能实现
Mixin类的祖先类也应该是Mixin类
使用Mixin类通常在继承列表中的第一个位置

浙公网安备 33010602011771号