第7.3节 Python特色的面向对象设计:协议、多态及鸭子类型
Python是一种多态语言,其表现特征是:对象方法的调用方只管方法是否可调用,不管对象是什么类型,从而屏蔽不同类型对象之间的差异,写出通用的代码,做出通用的编程,以适应需求的不断变化。
一、 Python中的协议
Python中定义某种类型是以实现了该类型对应的协议为标准的,如 可迭代对象(Iterable) 是指实现了可迭代协议的对象类型,迭代器是实现了迭代器协议的对象类型,序列是实现了序列协议的对象类型,那么具体协议是什么呢?在Python中协议是指一个或一组可供外部访问对象的特定方法(也有把对象属性作为协议的一部分,但老猿并不推荐这种使用方式),如可迭代对象是指容器中的元素可以通过__iter__( )方法或__getitem__( )方法访问,迭代器协议必须是定义和实现了__iter__()方法和next()方法,序列协议必须实现__len__()和getitem()方法。
协议是正式的,没有强制力,可以根据具体场景实现一个具体协议的一部分。例如,为了支持迭代,只需实现__getitem__,不需要实现__len__。
二、 “鸭子类型”与多态
从Python中协议的使用可以得出,Python中的对象类型不是简单的以类型定义区分的,而是以对象是否提供了特定的访问方法来确认的。凡是实现了类型要求的方法的对象都可以看做遵守类型对应协议,就是该类型的对象,老猿理解这是Python中多态的本质,这种以协议确认类型的方法所确认的类型就是“鸭子类型”(Duck typing)。
为什么说是“鸭子类型”呢?这个所有关于“鸭子类型”介绍的文章都有共同的介绍,在这复述一下:
鸭子类型(英语:duck typing)是动态类型的一种风格。在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由"当前方法和属性的集合"决定。
鸭子类型这一名字出自美国James Whitcomb Riley(有的材料说他是诗人,有的说他是测试人员,在此就不探究了)提出的如下的表述:
“When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck.”当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。
简单归纳就是:对象的类型不再由继承等方式决定,而由实际运行时所表现出的具体行为来决定。
以下为定义的鸭子类型与人类型,它们都有相同的方法:
class Duck():
def walk(self):
print('I walk like a duck')
def swim(self):
print('I swim like a duck')
def quack(self):
print('I quack like a duck')
class Person():
def walk(self):
print('this one walk like a duck')
def swim(self):
print('this man swim like a duck')
def quack(self):
print('I quack like a duck')
类的定义语法在后面一节介绍,但大家应该明白上述两个类的定义。可以很明显的看出,Person类拥有跟Duck类一样的方法,当有一个函数调用Duck类,并利用到了三个方法walk()、swim()和quack()。我们传入Person类也一样可以运行,函数并不会检查对象的类型是不是Duck,只要他拥有这三个方法,就可以正确的被调用。
为什么Python的多态是由“鸭子类型”来实现呢?这是由于Python属于动态语言,Python在定义变量时不指定变量的类型,而是由解释器根据变量内容推断变量类型的(也就是说变量的类型取决于所关联的对象),因此Python在判断变量类型时是看变量所具有的功能(方法)来决定。这就造就了Python的这种非常神奇的多态和“鸭子类型”,也是开发者很喜欢的一种开放的程序开发风格。
三、 鸭子类型的优点
1. python中的鸭子类型允许我们使用任何提供所需方法的对象,而不需要迫使它成为一个子类;
2. 因为任何提供正确接口的对象都可以在python中交替使用,它减少了多态的一般超类的需求。继承仍然可以用来共享代码,但是如果所有被共享的都是公共接口,鸭子类型就是所有所需的。这减少了继承的需要,同时也减少了多重继承的需要;
3. 调用方只管调用,不管细节,不管对象是什么类型,从而可以屏蔽不同类型对象之间的差异,写出通用的代码,做出通用的编程,以适应需求的不断变化。
三、 鸭子类型编程的注意事项
1. “鸭子类型”关注是对象的方法,而不是类型,因此使用Python开发时,尽量不要使用诸如type、issubclass等函数显式地执行类型检查进行类型检查;
2. 在进行方法调用时,对于程序无法明确确认对象是否有相应方法时,可以使用异常捕获或者hasattr或callable检查所需的方法是否存在来确保对应方法可以正常调用。如果有个对象p,我们需要判断p是否有swim方法,有如下方式:
1) 使用hasattr,语句:if hasattr(p,'swim') :p.swim()
2) 使用callable,语句:if hasattr(p,'swim') and callable(p.swim):p.swim()
3) 使用callable,语句:if callable(getattr(p,'swim',None)):p.swim()
本节介绍了Python中协议和“鸭子类型”的概念,并说明了Python多态与“鸭子类型”的关系,同时分析了“鸭子类型”有点以及使用的注意事项。
老猿Python(https://blog.csdn.net/LaoYuanPython)系列文章用于逐步介绍老猿学习Python后总结的学习经验,这些经验有助于没有接触过Python的程序员可以很容易地进入Python的世界。
欢迎大家批评指正,谢谢大家关注!
第7.3节 Python特色的面向对象设计:协议、多态及鸭子类型的更多相关文章
- Python面向对象04 /封装、多态、鸭子类型、类的约束、super
Python面向对象04 /封装.多态.鸭子类型.类的约束.super 目录 Python面向对象04 /封装.多态.鸭子类型.类的约束.super 1. 封装 2. 多态 3. 鸭子类型 4. 类的 ...
- python 面向对象专题(四):封装、多态、鸭子类型、类的约束、super
https://www.cnblogs.com/liubing8/p/11321099.html 目录 Python面向对象04 /封装.多态.鸭子类型.类的约束.super 1. 封装 2. 多态 ...
- PythonI/O进阶学习笔记_3.1面向对象编程_python的多态和鸭子类型
前言: 与第一篇的面向对象内容不同的是,第一篇中的面向对象更多的是与类.对象结合起来的概念粗浅理解,就是在编程历史中诞生的一种思想方法. 这篇的面向对象编程,更多落实到在语言设计实现中,是如何体现面向 ...
- Python面向对象----多态和鸭子类型
1. C#中多态实现的条件是 继承, 重写以及父类指向子类. 但是在弱类型Python里面, 实现多态的条件就显得很简洁, 只需要在子类中实现父类相同名称的方法即可. 2. 鸭子类型的解释: 若一个类 ...
- python面向对象-封装-property-接口-抽象-鸭子类型-03
封装 什么是封装: # 将复杂的丑陋的隐私的细节隐藏到内部,对外提供简单的使用接口 或 # 对外隐藏内部实现细节,并提供访问的接口 为什么需要封装 1.为了保证关键数据的安全性 2.对外部隐藏内部的实 ...
- python基础语法17 面向对象4 多态,抽象类,鸭子类型,绑定方法classmethod与staticmethod,isinstance与issubclass,反射
多态 1.什么是多态? 多态指的是同一种类型的事物,不同的形态. 2.多态的目的: “多态” 也称之为 “多态性”,目的是为了 在不知道对象具体类型的情况下,统一对象调用方法的规范(比如:名字). 多 ...
- python学习-60 面向对象设计
面向对象设计 1.三大编程范式 --面向过程编程 --函数式编程 --面向对象编程 2.编程进化论 --编程最开始就是无组织无结构,从简单控制流中按步写指令 --从上述的指令中提取重复的代码快或逻辑, ...
- python学习笔记-面向对象设计
前言 1.三大编程范式: 面向过程编程 函数式编程 面向对象编程 2.编程进化论 1.编程最开始就是无组织无结构,从简单控制流中按步写指令 2.从上述的指令中提取重复的代码块或逻辑,组织到一起,便实现 ...
- Python多态、鸭子类型
一.多态 多态指的是一类事物有多种形态. 动物有多种形态:人,狗,猪 import abc class Animal(metaclass=abc.ABCMeta): #同一类事物:动物 @abc.ab ...
随机推荐
- 剑指offer之顺序打印数组
算法的要求为: 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打 ...
- js 自适应手机电脑 轮播图
自己写了一个javascript的可循环轮播图,支持手机滑动,不过代码着实小白,全局变量,函数调用满天飞,研究别的代码规范好的轮播图插件,表示看得懂但是写不出.. HTML: <div id=& ...
- ERP的主数据的操作与设计--开源软件诞生25
赤龙ERP主数据管理讲解--第25篇 用日志记录"开源软件"的诞生 [进入地址 点亮星星]----祈盼着一个鼓励 博主开源地址: 码云:https://gitee.com/redr ...
- 交换机基于接口划分VLAN(汇聚层设备作为网关)
组网图形 简介 划分VLAN的方式有:基于接口.基于MAC地址.基于IP子网.基于协议.基于策略(MAC地址.IP地址.接口).其中基于接口划分VLAN,是最简单,最常见的划分方式,如接入层设备作为网 ...
- 内网渗透 day1-基础
粘滞键和放大镜 1. 到/windows/system32下用takeown改变该文件夹下的文件拥有权(因为粘滞键和放大镜都在system32文件夹下) cd /Windows/system32 ...
- 将CSV的数据发送到kafka(java版)
欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...
- 睿象云:为什么 Zabbix 告警如此火热?
每当我们谈及监控工具的时候,Zabbix 总是最惹人瞩目的那一个.如同清晨荷叶上的剔透露珠,卓尔不凡:如同巷子末头的百年酒香,让人倾心.我们都知道 Zabbix 是监控工具里当仁不让的龙头大哥,却没几 ...
- fastapi+vue搭建免费代理IP网站部署至heroku
说明 最近需要用到一些HTTP的代理,用于爬虫去爬取信息,搜索了一些网站,貌似现在这类提供免费代理IP的网站很多,刚好最近看了点vue的视频,弄个网站练练. 部署到heroku,预览地址:点击这里 F ...
- 精尽 MyBatis 源码分析 - MyBatis 初始化(三)之 SQL 初始化(上)
该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...
- 面试官:小伙子,给我说一下Java 数组吧
Java 数组 Java 语言中提供的数组是用来存储固定大小的同类型元素. 1.声明数组变量 首先必须声明数组变量,才能在程序中使用数组. dataType[] arrayRefVar; // 首选的 ...