Python不同版本的类
Python2.2之前是没有共同的祖先的,之后,引入obect类,它是所有类的共同祖先类object.
Python2中为了兼容,分为古典类(旧式类)和新式类.
Python中全部都是新式类
新式类都是继承自object的,新式类可以使用super.
多继承
ocp原则:多用"继承",少修改
继承的用途:在子类上实现对基类的增强,实现多态
- 多态
在面向对象中,父类,子类通过继承练习在一起,如果可以通过一套方法,就可以实现不同的表现,就是多态.
一个类继承自多个类就是多继承,它将具有多个类的特征.
多继承弊端
多继承很好的模拟了世界,因为食物很少是单一继承,但是舍弃简单,必然引入复杂性,带来了冲突.
如同一个孩子继承了来自父母双方的特征,那么究竟更像谁一点?
多继承的实现会导致编译器设计的复杂性增加,所以有些该机编程语言舍弃了类的多继承.
C++支持多继承;Java舍弃了多继承.
Java中,一个类可以实现多个接口,一个接口也可以继承多个接口.java的接口很纯粹,只是方法的声明,继承者必须实现这些方法,就具有这些能力;就能干什么
多继承可能会带来二义性,例如,猫和狗都继承自动物类,现在如果一个类多继承了猫和狗类,猫和狗都有shout方法,子类究竟继承谁的shout
解决方案
实现多继承语言,要解决二义性,深度优先或者广度优先
Python多继承实现
class ClassName(基类列表):
类体
多继承带来路径选择问题,究竟继承哪个父类的特征呢
Python使用MRO(method resolution order方法解析顺序)解决基类搜索顺序问题.
- 历史原因,MRO有三个搜索算法
经典算法,按照定义从左到右,深度优先策略.2.2版本之前
新式类算法,是经典算大的升级,深度优先,重复的只保留最后一个,2.2版本
C3算法,在类被创建出来的时候,就计算出一个MRO有序类表,2.3之后,Python3唯一支持的算法
C3算法解决多继承的二义性
经典算法右很大的问题,如果C中右覆盖A的方法,就不会访问到了,因为先访问A(深度优先).
新式类算法,依然采用了深度优先,解决了重复问题,但是同经典算法一样,没有解决继承的单调性.
C3算法,解决了继承的单调性,它阻止创建之前版本擦生二义性的代码.求得的MRO本质是为了鲜花行,且确定了顺序
单调性:假设有ABC三个类,C的MRO是[C,A,B],那么C的子类的mro中,A,B的孙旭一直就是单调的.
多继承的缺点
当类很多,继承复杂的情况下,继承路径太多,很难说清什么样的继承路径.
Python语法是允许多继承,但Python代码是解释执行,只有执行到的时候,才发现错误.
团队协作开发,如果引入多继承,那代码很有可能不可控.
不管编程语言是否支持多继承,都应当避免多继承.
Python的面向对象,我们看到的太灵活了,太开放了,所以要团队守规矩
mixin
文档Document类是其他所有文档类的抽象基类;
Word,Pdf类是Docunent的子类
需求:为了Document子类提供打印能力
思路:
1,在Document中提供print方法
假设已经有了下面3个类
class Document:
def __init__(self,content):
self.content = content
def print(self):
raise NotADirectoryError
class Word(Document):pass
class Pdf(Document):pass
基类提供的方可以不具体实现,因为它未必适合子类的打印,子类中需要覆盖重写.
基类中只定义,不实现的方法,称为"抽象方法".在Python中,如果采用这种方式定义的抽象方法,子类可以不实现,直到子类使用该方法的时候才报错.
print算是一种能力—打印功能,不是所有的Document的子类都需要的,所以,从这个角度出发,上面的基类Docunent设计有点问题.
2,需要打印的子类上增加
如果在现有子类Word或Pdf上直接增加,虽然可以,却违反了OCP的原则,所以可以继承后增加打印功能.
class Document:
def __init__(self,content):
self.content = content
class Word(Document):pass
class Pdf(Document):pass
# 单继承
class PrintableWord(Word):
def print(self):
print(self.content)
print(PrintableWord.__dict__)
print(PrintableWord.mro())
PW = PrintableWord('test string')
PW.print()
看似不错,如果需要还要提供其他功能,如何继承?
例如,如果该类用于网络,还应具备序列化的能力,在类上就应该实现序列化.
可序列化还可能分为pickle,json.messagepack等
这个时候发现,为了增加一种能力,就要增加意次继承,类可能太多了,继承的方式不是很好了.
功能太多,A类需要某几样功能,B类需要另几样功能,它们需要的是多个功能的只有组合,继承实现很繁琐.
3,装饰器
用装饰器增强一个类,把功能给类附加上去, 那个类需要,就装饰它
def printable(cls):
def _print(self):
print(self.content,'装饰器')
cls.print = _print
return cls
class Document:
def __init__(self, content):
self.content = content
class Word(Document):pass
class Pdf(Document):pass
@printable
class PrintableWord(Word):pass
print(PrintableWord.__dict__)
print(PrintableWord.mro())
PW = PrintableWord('test string')
PW.print()
@printable
class PrintablePdf(Pdf):pass
PW = PrintablePdf('test Pdf')
PW.print()
优点:
简单方便,在需要的地方动态增加,直接使用装饰器.
可以为类灵活的增加功能.
4,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.contrnt,'Mixin')
class PrintableWord(PrintableMixin,Word):pass
print(PrintableWord.__dict__)
print(PrintableWord.mro())
def printable(cls):
def _print(self):
print(self.content, '装饰器')
cls.print = _print
return cls
@printable
class PrintablePdf(Pdf):pass
print(PrintablePdf.__dict__)
print(PrintablePdf.mro())
Mixin就是其他类混合进来,同时带来了类的属性和方法.
这里看来Mixin类和装饰器效果一样,也没有什么特别的,但是Mix是类,就可以继承
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.__dict__)
print(PrintableWord.mro())
PW = PrintableWord('test string')
PW.print()
class SuperPrintableMixin(PrintableMixin):
def print(self):
print('~' * 30)
super().print()
print('~' * 30)
class SuperPrintablePdf(SuperPrintableMixin,Pdf):pass
print(SuperPrintablePdf.__dict__)
print(SuperPrintablePdf.mro())
PW = SuperPrintablePdf('test string')
PW.print()
Mixin类
Mixin本质上就是多继承实现的.
Mixix体现的是一种组合的设计模式.
在面向对象中,一个复杂的类,往往需要很多功能,而这些功能来自不同类提供,这就需要很多的类组合在一起.
从设计模式的角度来说,多组合,少继承
Mixin类的使用原则
- Mixin类中不应该显示的出现__init__初始化方法
- Mixix类同窗不能独立工作,因为它是准备混入别的类中的部分功能实现
- Mixin类的祖先也应是Mixin类
使用时,Mixib类通常在继承列表的第一个位置,例如class Printableword(PrintableMixin,word):pass
Mixib类和装饰器
这两种方式都可以使用,看个人喜好
如果还继续hi成就得使用Mixin的方式