美文网首页
Python:多态、鸭子模型和抽象基类

Python:多态、鸭子模型和抽象基类

作者: dex0423 | 来源:发表于2020-07-20 01:56 被阅读0次

1. 多态

  • 什么是多态
    -- 多态,指的是一种事务具有多种形态;
    -- python是一种动态语言,默认支持多态,同一个方法 调用 不同的类对象 ,执行的 结果各不相同

  • 多态实现
    -- 继承:不同子类 继承 同一父类
    -- 重写:子类重写 同一个方法,保证执行结果各不相同;

  • 示例
    -- 有如下代码:


>>> class Animals():
...     def talk(self):
...         print("Animal talk")
...
>>>
>>> class People(Animals):   # 继承 Animals 类
...     def talk(self):
...         print('People speak language')
...
>>>
>>> class Cat(Animals):      # 继承 Animals 类
...     def talk(self):
...         print('Cat say miaomiao')
...
>>>
>>> cat = Cat()
>>> peo = People()
>>>
>>> cat.talk()  # 调用 talk 方法
Cat say miaomiao
>>> peo.talk()  # 调用 talk 方法
People speak language

  • 如上所示:
    -- cat 和 peo 两个对象调用同一个 talk() 方法;
    -- 最后得到两种不同的结果;
  • 多态的优点:
    -- 多态可以增加代码的灵活度;
    -- 是调用方法的技巧,不会影响到类的内部设计;
    -- 多态可以看做 接口函数的重用同一种接口方法 通过 接收不同的类 对象,从而实现不同的功能;
  • 多态使用场景:
    -- 方法参数接收同一父类的不同子类对象。

2. 鸭子模型

  • 什么是鸭子模型
    -- 当看到一只鸟走起来像鸭子,游泳起来也像鸭子,叫起来也像鸭子,那么这只鸟就可以被称为鸭子;
    -- 鸭子模型和多态一样,都是接受不同的类对象,并调用相同的方法(即:鸭子的 游泳 和 叫 方法);
    -- 对于一个鸭子模型来说,我们并 不关心接收的类对象是否真的是鸭子类,只关心这个类是如何被使用的;
    -- 注意:如果这些需要被调用的方法不存在,那么将引发一个运行时错误。

  • 示例
    -- 有如下代码:


>>> class Duck:
...     def quack(self):
...         print("duck quack")
...
>>>
>>> class Bird:    # Bird 类与 Duck 类无继承关系
...     def quack(self):
...         print("bird quack")
...
>>>
>>> class Dog:     # Dog类与 Duck 类无继承关系
...     def quack(self):
...         print("dog quack")
...
>>>
>>> def animal_quack(animal):    # animal_quack 方法可以调用任何对象的 quack() 方法,不关心对象是谁
...     animal.quack()
...
>>>
>>> duck = Duck()
>>> bird = Bird()     # bird 实例与 duck 实例无任何关系
>>> dog = Dog()       # dog 实例与 duck 实例无任何关系
>>>
>>> for animal in [duck, bird, dog]:
...     animal_quack(animal)
...
duck quack
bird quack
dog quack

-- 如上所示:
-- duck、bird、dog 分别来自三个不同的类,而且类之间是 没有继承关系 的;
-- duck、bird、dog 调用 animal_quack 方法,得到三种不同的结果,符合多态的特征;

  • 鸭子模型的优点:
    -- 鸭子模型不关关心类对象是什么,不需要类之间具有继承关系;
    -- 鸭子模型让代码比多态更加灵活度;
  • 多态使用场景:
    -- 鸭子模型中,接收不同的类将会产生不同的行为,而无须明确知道这个类实际上是什么,这是多态的重要应用场景;
    -- 实际生产环境中,主要用于 接口开发,即用同一个函数接收不同的类对象,从而实现不同的功能,而且无需关注对象之间的继承关系;

3. 抽象基类

  • 什么是抽象基类
    -- 抽象基类,这个词可能听着比较"深奥",其实 抽象 就是 假 的意思,基类 就是 父类,抽象基类 就是 假父类;
    -- 具体来说,由 abc.ABCMeta 这个元类实现的类,就是抽象基类;
  • 示例:
    -- 如下代码中的 AbstractClass 类继承自 abc.ABCMeta,AbstractClass 就是抽象基类;

class AbstractClass(metaclass=abc.ABCMeta):
    pass

  • 抽象基类的作用
    -- 判断是否为某个对象的实例

>>> class MyList(object):
...     def __init__(self, my_list):
...         self.my_list= my_list
...     def __len__(self):
...         return len(self.my_list)
...
>>>
>>> class NewList(MyList):    # NewList 继承自 MyList
...     pass
...
>>> ml = MyList(["a", "b", "c"])
>>>
>>> from collections.abc import Sized, Iterable
>>>
>>> print(isinstance(ml, Sized))  
True             # 返回 True,因为这里会检查实例对象中有没有__len__方法,有即输出True
>>> nl = NewList([1, 2, 3])
>>> print(isinstance(nl, MyList))
True             # 返回 True,因为 nl 实例化的类 NewList 同时也是 MyList 的子类

-- 强制要求父类被子类继承,并在子类实现某个方法,否则子类初始化时就会报错;


>>> from abc import ABCMeta,abstractmethod
>>>
>>>
>>> class Source(metaclass=ABCMeta):              # 创建抽象基类 Source
...     @abstractmethod                           # 表示装饰的方法必须被子类所实现,否则会报错 
...     def get(self,key):
...         pass
...
>>>
>>> class Mysource(Source):                       # 子类 Mysource 继承自 抽象基类 Source
...     def get(self,key):                        # 实现 get 方法,这个方法是 抽象基类 Source 强制要求实现的
...         pass
...
>>>
>>> class Mysource1(Source):                      # 子类 Mysource1 没有实现 抽象基类 Source 强制要求实现的 get 方法
...     pass
...
>>> test = Source()         # test 直接实例化 Source 父类                 
Traceback (most recent call last):                          # 此处报错,因为抽象类无法实现实例化
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class Source with abstract methods get
>>> 
>>> test = Mysource()                                       # 此处实例化 Mysource,未报错
>>> 
>>> test = Mysource1()                         
Traceback (most recent call last):                          # 报错,继承类必须实现抽象类的方法
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class Mysource1 with abstract methods get

  • 抽象基类使用场景
    -- 接口强制规定,主要是 强制子类实现某个方法,否则就提示报错;
  • 抽象基类的有点:
    -- 处理继承问题方面更加规范、系统;
    -- 明确调用之间的相互关系,使得继承层次更加清晰;
  • 抽象基类的缺点:
    -- 抽象基类在 python 并非在于用来继承,主要用来理解 python继承 的定义,应该 尽量使用鸭子模型
    -- 如果一定要继承接口的话,比较 推荐多继承,抽象基类容易 设计过度

相关文章

  • Python:多态、鸭子模型和抽象基类

    1. 多态 什么是多态-- 多态,指的是一种事务具有多种形态;-- python是一种动态语言,默认支持多态,同一...

  • 深入理解 Python 类和对象(2) - 抽象基类

    抽象基类,即 Python 中的 abc 模块,Abstract Base Class。 Python 抽象基类可...

  • python高级编程第一讲:深入类和对象

    1.鸭子类型和多态 多态的概念是应用于Java和C#这一类强类型语言中,而Python崇尚"鸭子类型" 所谓多态:...

  • python鸭子类型

    抽象类,多态与鸭子类型 - 独角兕大王 - 博客园

  • 文本查询程序

    //面向对象的核心是,抽象继承多态。抽象把数据实现隐藏,暴露公共接口继承和多态,派生类继承基类,降低代码重复性,通...

  • 10.26学习总结

    今天学习了多态和抽象类。 多态学了虚方法、方法的重写,多态和继承的区别,重写和隐藏的区别。 抽象类学了抽象类的方法...

  • 多态的意义和操作过程

    多态 首先Python不支持多态,也不用支持多态,python是一种多态语言,崇尚鸭子类型。以下是维基百科中对鸭子...

  • 深入理解 Python 类和对象(1) - 鸭子类型和多态

    什么是鸭子类型? Java 中实现多态,需要继承父类,并覆盖父类中的方法。 Python 中实现多态,不需要继承任...

  • 2017.10.26  C#

    今天老师主要讲了两大方面:多态和抽象方法 在多态中主要是虚方法和方法重写 在基类中使用 virtual 关键字定义...

  • python抽象基类

    有时,我们抽象出一个基类,知道要有哪些方法,但只是抽象方法,并不实现功能,只能继承, 而不能被实例化,但子类必须要...

网友评论

      本文标题:Python:多态、鸭子模型和抽象基类

      本文链接:https://www.haomeiwen.com/subject/demdkktx.html