Python中的鸭子类型
今天,我们来聊一聊Python中的鸭子类型(duck typing)。
编程语言具有类型概念,例如Python中有数字类型、字符串类型、布尔类型,或者更加复杂的结构,例如元组tuple、列表list、集合set和字典类型dict等等。
根据如何将类型解析并赋值给各种构造(例如变量,表达式,函数,函数参数等),编程语言可以归类为“鸭子类型”,“结构化类型”或“标称类型”。
本质上,分类决定了对象如何被解析并推断为具体的类型。
鸭子测试
鸭子类型(duck typing)语言使用鸭子测试来评估对象是否可以被解析为特定的类型。Python就是其中一种。
这个概念的名字来源于由詹姆斯·惠特科姆·莱利提出的鸭子测试。“鸭子测试”可以这样表述:
“如果看起来像鸭子,叫起来像鸭子,那么它一定是鸭子。”
If it looks like a duck and quacks like a duck, it must be a duck.
James Whitcomb Riley

鸭子类型
鸭子类型在程序设计中是动态类型的一种风格。在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由"当前方法和属性的集合"决定。
在鸭子类型中,关注点在于对象的行为,能作什么;而不是关注对象所属的类型。例如,在不使用鸭子类型的语言中,我们可以编写一个函数,它接受一个类型为"鸭子"的对象,并调用它的"走"和"叫"方法。在使用鸭子类型的语言中,这样的一个函数可以接受一个任意类型的对象,并调用它的"走"和"叫"方法。如果这些需要被调用的方法不存在,那么将引发一个运行时错误。任何拥有这样的正确的"走"和"叫"方法的对象都可被函数接受的这种行为引出了以上表述,这种决定类型的方式因此得名。
鸭子类型通常得益于"不"测试方法和函数中参数的类型,而是依赖文档、清晰的代码和测试来确保正确使用。
在常规类型中,我们能否在一个特定场景中使用某个对象取决于这个对象的类型,而在鸭子类型中,则取决于这个对象是否具有某种属性或者方法——即只要具备特定的属性或方法,能通过鸭子测试,就可以使用。
Python术语
Python术语表中的鸭子类型duck-typing:
A programming style which does not look at an object’s type to determine if it has the right interface; instead, the method or attribute is simply called or used (“If it looks like a duck and quacks like a duck, it must be a duck.”) By emphasizing interfaces rather than specific types, well-designed code improves its flexibility by allowing polymorphic substitution. Duck-typing avoids tests using type() or isinstance(). (Note, however, that duck-typing can be complemented with abstract base classes.) Instead, it typically employs hasattr() tests or EAFP programming.
译文:
鸭子类型是一种编程风格,决定一个对象是否有正确的接口,关注点在于它的方法或属性,而不是它的类型(“如果它看起来像鸭子,像鸭子一样嘎嘎叫,那么它一定是鸭子。”)。通过强调接口而不是特定类型,设计良好的代码通过多态提高了灵活性。鸭子类型无需使用
type()或isinstance()进行检查(注意,鸭子类型可以用抽象基类来补充),相反,它通常使用hasattr()来检查,或是 EAFP 编程。
代码示例
举个例子:
# 定义一个计算函数,接收3个入参
def calculate(a, b, c):
return (a + b) * c
# 分别计算3种情况的结果
result1 = calculate(1, 2, 3)
result2 = calculate([1, 2, 3], [4, 5, 6], 2)
result3 = calculate("打工人", "打工魂", 3)
# 打印3种结果
print(result1, result2, result3, sep='\n')
代码解释:在上面的例子中,我们每次调用calculate()都使用的是不同的对象(数字、列表和字符串),并且它们在继承关系中没有联系。只要输入对象支持+和*方法,操作就能成功。
执行后输出:
9
[1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6]
打工人打工魂打工人打工魂打工人打工魂
这样,鸭子类型在不使用继承的情况下使用了多态。
再举个栗子:
# 鸭子类
class Duck:
def quack(self):
print("这鸭子正在嘎嘎叫")
def feathers(self):
print("这鸭子拥有白色和灰色的羽毛")
# 人类
class Person:
def quack(self):
print("这人正在模仿鸭子")
def feathers(self):
print("这人在地上拿起1根羽毛然后给其他人看")
# 函数/接口
def in_the_forest(duck):
duck.quack()
duck.feathers()
if __name__ == '__main__':
donald = Duck() # 创建一个Duck类的实例
john = Person() # 创建一个Person类的实例
in_the_forest(donald) # 调用函数,传入Duck的实例
in_the_forest(john) # 调用函数,传入Person的实例
代码运行后输出:
这鸭子正在嘎嘎叫
这鸭子拥有白色和灰色的羽毛
这人正在模仿鸭子
这人在地上拿起1根羽毛然后给其他人看
总结
鸭子类型是一个与动态类型(dynamic typing)相关的概念,其中关注的是它定义的方法,而不太关注对象的类型或所属类。当您使用鸭子类型时,你无需做检查类型。相反,您要检查给定方法或属性是否存在。
鸭子类型语言为程序员提供了最大的灵活性,程序员只需写最少量的代码。但是这些语言可能并不安全,可能会产生运行时错误,使用时需要格外注意。
参考链接:
- Python术语表:https://docs.python.org/3/glossary.html#term-duck-typing
- 维基百科:https://zh.wikipedia.org/wiki/鸭子类型
Python中的鸭子类型的更多相关文章
- Python 中的鸭子类型和猴子补丁
原文链接: Python 中的鸭子类型和猴子补丁 大家好,我是老王. Python 开发者可能都听说过鸭子类型和猴子补丁这两个词,即使没听过,也大概率写过相关的代码,只不过并不了解其背后的技术要点是这 ...
- Python多态、鸭子类型
一.多态 多态指的是一类事物有多种形态. 动物有多种形态:人,狗,猪 import abc class Animal(metaclass=abc.ABCMeta): #同一类事物:动物 @abc.ab ...
- python语言的鸭子类型和强类型语言的多态
python语言的鸭子类型和强类型语言的多态 前面讲接口类的时候举过一个有关支付方式的例子,支付方式可以有几种,微信支付,支付宝支付,苹果支付等,这几个不同的支付都统一于支付,像这样几个类都统一于 某 ...
- Python中内置数据类型list,tuple,dict,set的区别和用法
Python中内置数据类型list,tuple,dict,set的区别和用法 Python语言简洁明了,可以用较少的代码实现同样的功能.这其中Python的四个内置数据类型功不可没,他们即是list, ...
- Python 中的枚举类型~转
Python 中的枚举类型 摘要: 枚举类型可以看作是一种标签或是一系列常量的集合,通常用于表示某些特定的有限集合,例如星期.月份.状态等. 枚举类型可以看作是一种标签或是一系列常量的集合,通常用于表 ...
- python中对象、类型和元类之间的关系
在python中对象.类型和元类构成了一个微妙的世界. 他们有在这个世界里和平共处,相辅相成.它们遵循着几条亘古不变的定律: 1.python中无处不对象 2.所有对象都有三种特性:id.类型.值 3 ...
- Python中的集合类型分类和集合类型操作符解析
集合类型 数学上,把set称作由不同的元素组成的集合,集合(set)的成员通常被称作集合元素(set elements). Python把这个概念引入到它的集合类型对象里.集合对象是一组无 ...
- python多态和鸭子类型
多态与多态性 多态指的是一类事物有多种形态,(一个抽象类有多个子类,因而多态的概念依赖于继承). 比如:文件分为文本文件,可执行文件(在定义角度) 比如 我们按下 F1 键这个动作: 如果当前在 Fl ...
- Python - 协议和鸭子类型
参考: Fluent_Python - P430 wiki 这里说的协议是什么?是让Python这种动态类型语言实现多态的方式. 在面向对象编程中,协议是非正式的接口,是一组方法,但只是一种文档,语言 ...
随机推荐
- [LeetCode]13.罗马数字转整数(Java)
原题地址: roman-to-integer 题目描述: 罗马数字包含以下七种字符: I, V, X, L,C,D 和 M. 字符 数值 I 1 V 5 X 10 L 50 C 100 D 500 M ...
- CreateEvent进程同步
CreateEvent进程间同步 CreateEvent可以创建或是打开一个命名或是未命名的event对象. HANDLE CreateEvent( LPSECURITY_ATTRIBUTES ...
- suse 12 双网卡bonding模式
文章目录 工欲善其事,必先配静态ip 网卡bonding eth0 eth1 192.168.70.52 192.168.70.55 工欲善其事,必先配静态ip 重要的事情说三遍 修改配置之前,先备份 ...
- [LeetCode]1313. 解压缩编码列表
给你一个以行程长度编码压缩的整数列表 nums . 考虑每对相邻的两个元素 [freq, val] = [nums[2i], nums[2i+1]] (其中 i >= 0 ),每一对都表示解压后 ...
- 实践GoF的23种设计模式:SOLID原则(上)
摘要:本文以我们日常开发中经常碰到的一些技术/问题/场景作为切入点,示范如何运用设计模式来完成相关的实现. 本文分享自华为云社区<实践GoF的23种设计模式:SOLID原则(上)>,作者: ...
- [数分笔记]问题1.1 T1
题目:非负整数a,b使得为整数,求证这个整数必是某一整数的平方.(1988年第29届国际数学奥林匹克竞赛试题) 证明:设k=,k为非负整数 1°a=b k=2a²/(1+a²)=2-2/(1+a²) ...
- Python:在一个Python程序中,运行另一个Python程序
学习自: 1~3学习自如何在python中执行另一个py文件_python_脚本之家 4~6学习自Python中四种运行其他程序的方式 - hankleo - 博客园 1.os.system方法 用法 ...
- 获取HTML中所有图片的 URL
/// <summary> /// 获取HTML中所有图片的 URL /// </summary> /// <param name="strHtml" ...
- 操作Jexus
jws.start等命令在Jexus V5.6.3中已经合并为一个单一命令,即"jws",这是一个shell脚本文件. 命令参数与对应的功效: jws start : 启动Jexu ...
- consul-常用命令
1.consul 是B/C架构.服务端和客户端包是一样的.差别在于启动时候的参数. --客户端 ./consul agent -join=172.29.2.65:8301 -bind=172.29.3 ...