第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 ...
随机推荐
- Android Google官方文档(cn)解析之——Intents and Intent filter
应用程序核心组件中的三个Activity,service,还有broadcast receiver都是通过一个叫做intent的消息激活的.Intent消息传送是在相同或不同的应用程序中的组件之间后运 ...
- leetcode117:search-rotated-sorted-array
题目描述 给出一个转动过的有序数组,你事先不知道该数组转动了多少 (例如,0 1 2 4 5 6 7可能变为4 5 6 7 0 1 2). 在数组中搜索给出的目标值,如果能在数组中找到,返回它的索引, ...
- 这些C++基础知识的基础知识你都学会了吗?
一.C++基础知识 新的数据类型 C语言中的数据类型 C++中新的数据类型 思考:新的数据类型有什么好处?请看下面的代码: 可以见得:新的类型使整个程序更加简洁,程序变得易读易懂!这个就是bool ...
- 编程,向内存0:200~0:23F依次传送数据0~63(3FH),程序中只能使用9条指令,9条指令包括 mov ax,4c00h 和 int 21h
assume cs:code code segment mov bx,020H mov ds,bx mov bx,0 mov cx,63 s:mov [bx],bx inc bx loop s mov ...
- pthread 多线程基础
本文主要介绍如何通过 pthread 库进行多线程编程,并通过以下例子进行说明. 基于莱布尼兹级数计算 \(\pi\) . 多线程归并排序 参考文章: [1] https://computing.ll ...
- linux nf_conntrack 连接跟踪机制
PRE_ROUTING和LOCAL_OUT点可以看作是整个netfilter的入口,而POST_ROUTING和LOCAL_IN可以看作是其出口; 报文到本地:PRE_ROUTING----LOCAL ...
- gcc 去除无用程序段
嵌入式系统中,对程序尺寸要求高时,可以使用本方法 代码中,经常会有一种情况,库中并非所有函数都会用到.然而,无用的函数也最终被编译进可执行文件中了. 为避免这一情况,可以在编译时,添加选项:-ffun ...
- Innodb之全局共享内存
参考链接: https://blog.csdn.net/miyatang/article/details/54881547 https://blog.csdn.net/wyzxg/article/de ...
- jwt鉴权学习 (php示例代码)
前段时间听朋友讲起 jwt鉴权,博主我是一脸懵逼,通过朋友坚持不懈的讲解,我终于听懂了,jwt就是登陆token校验嘛 然而事情并不是博主想象的那么简单,在一个艳阳高照,晴空万里的夜晚,博主手贱百度了 ...
- yum安装no more mirrors to try
先挂载:mount /dev/cdrom /mnt yum clean allyum makecacheyum -y update 后重试