Python实现多态、协议和鸭子类型的代码详解


Posted in Python onMay 05, 2019

多态

问起面向对象的三大特性,几乎每个人都能对答如流:封装、继承、多态。今天我们就要来说一说 Python 中的多态。

所谓多态:就是指一个类实例的相同方法在不同情形有不同表现形式。多态机制使具有不同内部结构的对象可以共享相同的外部接口。这意味着,虽然针对不同对象的具体操作不同,但通过一个公共的类,它们(那些操作)可以通过相同的方式予以调用。

我在《Python 中的设计模式详解之:策略模式》一文中详细描述了策略模式的实现,而策略模式就是典型的多态应用。

之前的代码我就不贴了,大家可以去原文中查看。我依然还是以商品折扣的经典举例。策略模式一文中,传统的策略模式实现方式我也是用 Python 代码实现的,在 java 或 C# 等语言中,实现方式也差不多。以下是 C# 代码,我只列了个架子:

interface Promotion
{
 double discount(Order order);
}
class FidelityPromo : Promotion // 第一个具体策略
{
 // 为积分为1000或以上的顾客提供5%折扣
 public double discount(Order order)
 {
  ...
 }
}
class BulkItemPromo : Promotion // 第二个具体策略
{
 //单个商品为20个或以上时提供10%折扣
 public double discount(Order order)
 {
  ...
 }
}
class LargeOrderPromo : Promotion // 第三个具体策略
{
 //订单中的不同商品达到10个或以上时提供7%折扣
 public double discount(Order order)
 {
  ...
 }
}

可以看到,首先要有一个接口(Promotion),然后各个策略去实现这个接口。然而,Python 语言没有 interface 关键字,就是说,Python 里没有像 java、C# 一样的接口。

在策略模式一文的实现中,使用了抽象基类(Abstract Base Class,ABC)来实现接口,这主要是为了写法上看起来和 java、C# 等语言更加的像,易于有这些语言基础的同学理解和对比。

抽象基类是在 Python 语言诞生 15 年后,Python 2.6 才引入的。这里我们不详细介绍抽象基类,因为即便现在也很少有代码使用抽象基类。对于多态,Python 有更好的实现方式——鸭子类型(duck typing)。

协议和鸭子类型

所谓 鸭子类型 就是:如果一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么它就是鸭子。这个概念的名字来源于 James Whitcomb Riley 提出的鸭子测试。

初次看到这个描述的小伙伴一定一头雾水,为了理解鸭子类型,我们不得不提到另一个名词——协议。

在面向对象编程中,协议是非正式的接口,是一组方法,只由文档和约定定义,因此,协议不能像正式接口那样施加强制性约束。而 Python 的哲学就是尽量支持基本协议。

翻译成人话,就是:Python 中没有接口,在需要使用接口的地方,就用协议代替。所谓协议,其实就是一组方法,和接口中定义的方法一个意思。只不过协议是不是强制性的约定,如果你不遵守协议,那么也没关系,运行时报错就是了。

这样就好理解鸭子类型了,“如果一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子” 这就表示已经遵守了协议,“那么它就是鸭子”,意味着你可以在其他用到“鸭子”的地方,用“这只鸟”替换。这不就是多态吗?

用“鸭子类型”来实现策略模式也很简单,删掉抽象基类就可以了。(这就是为什么抽象基类很少使用的原因,因为删掉代码也一样正确啊。)有兴趣的小伙伴可以自己尝试一下代码。

Python 中的协议举例

Python 中有很多的协议,比如迭代器协议,任何实现了 __iter__ 和 __next__ 方法的对象都可称之为迭代器,但对象本身是什么类型不受限制,这得益于鸭子类型。

from collections import Iterable
from collections import Iterator

class MyIterator:
 def __iter__(self):
  pass
 def __next__(self):
  pass
print(isinstance(MyIterator(), Iterable)) 
print(isinstance(MyIterator(), Iterator))

输出:

True
True

结语

鸭子类型是编程语言中动态类型语言中的一种设计风格,一个对象的特征不是由父类决定,而是通过对象的方法决定的。

Python 不是不支持多态,而是 Python 本身就是一门多态的语言。

Python 相关文章推荐
对于Python编程中一些重用与缩减的建议
Apr 14 Python
详解在Python程序中解析并修改XML内容的方法
Nov 16 Python
Python模块结构与布局操作方法实例分析
Jul 24 Python
利用Python在一个文件的头部插入数据的实例
May 02 Python
解决python大批量读写.doc文件的问题
May 08 Python
对python中if语句的真假判断实例详解
Feb 18 Python
python打印9宫格、25宫格等奇数格 满足横竖斜相加和相等
Jul 19 Python
Django多数据库的实现过程详解
Aug 01 Python
python中xlutils库用法浅析
Dec 29 Python
python 制作一个gui界面的翻译工具
May 14 Python
Python爬虫之自动爬取某车之家各车销售数据
Jun 02 Python
使用opencv-python如何打开USB或者笔记本前置摄像头
Jun 21 Python
用uWSGI和Nginx部署Flask项目的方法示例
May 05 #Python
基于python实现高速视频传输程序
May 05 #Python
Python远程视频监控程序的实例代码
May 05 #Python
Python统计一个字符串中每个字符出现了多少次的方法【字符串转换为列表再统计】
May 05 #Python
20行python代码实现人脸识别
May 05 #Python
使用python实现mqtt的发布和订阅
May 05 #Python
Python向excel中写入数据的方法
May 05 #Python
You might like
通过Email发送PHP错误的方法
2015/07/20 PHP
PHP树-不需要递归的实现方法
2016/06/21 PHP
JQuery 技巧和窍门整理(8个)
2010/04/22 Javascript
JS子父窗口互相操作取值赋值的方法介绍
2013/05/11 Javascript
关闭浏览器时提示onbeforeunload事件
2013/12/25 Javascript
js实现通用的微信分享组件示例
2014/03/10 Javascript
jQuery实现点击该行即可删除HTML表格行
2014/10/17 Javascript
jquery实现Ctrl+Enter提交表单的方法
2015/07/21 Javascript
js实现复选框的全选和取消全选效果
2017/01/03 Javascript
Vue.js在使用中的一些注意知识点
2017/04/29 Javascript
js,jq,css多方面实现简易下拉菜单功能
2017/05/13 Javascript
使用AngularJS对表单提交内容进行验证的操作方法
2017/07/12 Javascript
在vue-cli项目中使用bootstrap的方法示例
2018/04/21 Javascript
Vant Weapp组件踩坑:picker的初始赋值解决
2020/11/12 Javascript
[02:08]DOTA2英雄基础教程 马格纳斯
2014/01/17 DOTA
python matplotlib中文显示参数设置解析
2017/12/15 Python
Python 读取图片文件为矩阵和保存矩阵为图片的方法
2018/04/27 Python
python 从文件夹抽取图片另存的方法
2018/12/04 Python
Pandas时间序列重采样(resample)方法中closed、label的作用详解
2019/12/10 Python
python GUI库图形界面开发之PyQt5控件数据拖曳Drag与Drop详细使用方法与实例
2020/02/27 Python
Django项目uwsgi+Nginx保姆级部署教程实现
2020/04/19 Python
CSS3教程:新增加的结构伪类
2009/04/02 HTML / CSS
德国baby-markt婴儿用品瑞士网站:baby-markt.ch
2017/06/09 全球购物
最耐用行李箱,一箱永流传:Briggs & Riley(全球终身保修)
2017/12/07 全球购物
具有防紫外线功能的高性能钓鱼服装:Hook&Tackle
2018/08/16 全球购物
Stokke美国官方网店:高级儿童家具、推车、汽车座椅和配件
2020/06/06 全球购物
教师专业自荐书范文
2014/02/10 职场文书
岗位廉洁从业承诺书
2014/03/28 职场文书
详细的本科生职业生涯规划范文
2014/09/16 职场文书
工作期间打牌检讨书范文
2014/11/20 职场文书
三孔导游词
2015/02/05 职场文书
产品调价通知函
2015/04/20 职场文书
《语言的突破》读后感3篇
2019/12/12 职场文书
Maven学习----Maven安装与环境变量配置教程
2021/06/29 Java/Android
CSS 左边固定宽右边自适应的6种方法
2022/05/15 HTML / CSS
CSS控制继承中的height能变为可继承吗
2022/06/10 HTML / CSS