python-----------------------多继承

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的方式
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值