100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > python抽象基类的作用_Python:多态 鸭子模型和抽象基类

python抽象基类的作用_Python:多态 鸭子模型和抽象基类

时间:2023-01-17 09:22:11

相关推荐

python抽象基类的作用_Python:多态 鸭子模型和抽象基类

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 "", line 1, in

TypeError: Can't instantiate abstract class Source with abstract methods get

>>>

>>> test = Mysource() # 此处实例化 Mysource,未报错

>>>

>>> test = Mysource1()

Traceback (most recent call last): # 报错,继承类必须实现抽象类的方法

File "", line 1, in

TypeError: Can't instantiate abstract class Mysource1 with abstract methods get

抽象基类使用场景

-- 接口强制规定,主要是 强制子类实现某个方法,否则就提示报错;

抽象基类的有点:

-- 处理继承问题方面更加规范、系统;

-- 明确调用之间的相互关系,使得继承层次更加清晰;

抽象基类的缺点:

-- 抽象基类在 python 并非在于用来继承,主要用来理解 python继承 的定义,应该 尽量使用鸭子模型;

-- 如果一定要继承接口的话,比较 推荐多继承,抽象基类容易 设计过度;

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。