多态及鸭子类型

Posted wyh0717

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多态及鸭子类型相关的知识,希望对你有一定的参考价值。

多继承

# 背诵
# 只要继承object类就是新式类
# 不继承object类的都是经典类

# python3 所有的类都继承object类,都是新式类
# 在py2中 不继承object的类都是经典类
#          继承object类的就是新式类了

# 经典类 :在py3中不存在,在py2中不主动继承object的类
class A:
    def func(self):
        print(‘A‘)

class B(A):
    pass
    # def func(self):
    #     print(‘B‘)
class C(A):
    pass
    # def func(self):
    #     print(‘C‘)
class D(B,C):
    pass
    # def func(self):
    #     print(‘D‘)
print(D.mro())   # 只在新式类中有,经典类没有的
[<class ‘__main__.D‘>, <class ‘__main__.B‘>, <class ‘__main__.C‘>, <class ‘__main__.A‘>, <class ‘object‘>]
# 在走到一个点,下一个点既可以从深度走,也可以从广度走的时候,总是先走广度,再走深度,广度优先
# 在经典类中,都是深度优先,总是在一条路走不通之后再换一条路,走过的点不会再走了

C3算法

# C3算法
# A(O) = [AO]
# B(A) = [BAO]
# C(A) = [CAO]
# D(B) = [DBAO]
# E(C) = [ECAO]

# F(D,E) = merge(D(B) + E(C))
#          = [F] + [DBAO] + [ECAO]
#        F = [DBAO] + [ECAO]
#     FD   = [BAO] + [ECAO]
#     FDB  = [AO] + [ECAO]
#     FDBE = [AO] + [CAO]
#     FDBEC= [AO] + [AO]
#     FDBECA= [O] + [O]
#     FDBECAO

# 算法的内容
    # 如果是单继承 那么总是按照从子类->父类的顺序来计算查找顺序
    # 如果是多继承 需要按照自己本类,父类1的继承顺序,父类2的继承顺序,...
    # merge的规则 :如果一个类出现在从左到右所有顺序的最左侧,并且没有在其他位置出现,那么先提出来作为继承顺序中的一个
                # 或 一个类出现在从左到右顺序的最左侧,并没有在其他顺序中出现,那么先提出来作为继承顺序中的一个
                # 如果从左到右第一个顺序中的第一个类出现在后面且不是第一个,那么不能提取,顺序向后继续找其他顺序中符合上述条件的类

# 经典类 - 深度优先 新式类 - 广度优先
# 深度优先要会看,自己能搞出顺序来
# 广度优先遵循C3算法,要会用mro,会查看顺序
# 经典类没有mro,但新式类有

多态与鸭子类型

什么多态:同一事物有多种形态
为何要有多态=》多态会带来什么样的特性,多态性
    多态性指的是可以在不考虑对象具体类型的情况下而直接使用对象

多态指的是一类事物有多种形态,比如动物有多种形态:猫、狗、猪
class Animal: #同一类事物:动物
    def talk(self):
        pass
class Cat(Animal): #动物的形态之一:猫
    def talk(self):
        print(‘喵喵喵‘)
class Dog(Animal): #动物的形态之二:狗
    def talk(self):
        print(‘汪汪汪‘)
class Pig(Animal): #动物的形态之三:猪
    def talk(self):
        print(‘哼哼哼‘)

#实例化得到三个对象
>>> cat=Cat()
>>> dog=Dog()
>>> pig=Pig()   多态性指的是可以在不用考虑对象具体类型的情况下而直接使用对象,这就需要在设计时,把对象的使用方法统一成一种:例如cat、dog、pig都是动物,但凡是动物肯定有talk方法,于是我们可以不用考虑它们三者的具体是什么类型的动物,而直接使用
>>> cat.talk()
喵喵喵
>>> dog.talk()
汪汪汪
>>> pig.talk()
哼哼哼   综上我们得知,多态性的本质在于不同的类中定义有相同的方法名,这样我们就可以不考虑类而统一用一种方式去使用对象,可以通过在父类引入抽象类的概念来硬性限制子类必须有某些方法名
import abc

# 指定metaclass属性将类设置为抽象类,抽象类本身只是用来约束子类的,不能被实例化
class Animal(metaclass=abc.ABCMeta):
    @abc.abstractmethod # 该装饰器限制子类必须定义有一个名为talk的方法
    def talk(self): # 抽象方法中无需实现具体的功能
        pass

class Cat(Animal): # 但凡继承Animal的子类都必须遵循Animal规定的标准
    def talk(self):
        pass

cat=Cat() # 若子类中没有一个名为talk的方法则会抛出异常TypeError,无法实例化
   但其实我们完全可以不依赖于继承,只需要制造出外观和行为相同对象,同样可以实现不考虑对象类型而使用对象,
这正是Python崇尚的“鸭子类型”(duck typing):“如果看起来像、叫声像而且走起路来像鸭子,那么它就是鸭子”。
比起继承的方式,鸭子类型在某种程度上实现了程序的松耦合度,如下
#二者看起来都像文件,因而就可以当文件一样去用,然而它们并没有直接的关系
class Txt: #Txt类有两个与文件类型同名的方法,即read和write
    def read(self):
        pass
    def write(self):
        pass

class Disk: #Disk类也有两个与文件类型同名的方法:read和write
    def read(self):
        pass
    def write(self):
        pass

以上是关于多态及鸭子类型的主要内容,如果未能解决你的问题,请参考以下文章

python多态

Python面向对象编程——多态多态性鸭子类型

多态,鸭子模型

面向对象之组合封装多态性鸭子类型

多态/封装

鸭子类型-类的约束-异常处理