【Python】浅谈 鸭子类型 (Duck Typing)
目录
一、来源
二、说明
三、举例
四、不足
一、来源
在程序设计中,鸭子类型 (duck typing) 是动态类型的一种风格。在此风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由当前方法和属性的集合决定的。
事实上,duck typing 的概念源于一个米国诗人的诗句:
" 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."
—— James Whitcomb Riley
“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。”
—— 詹姆斯·惠特科姆·莱利
后来,工程师在 Python 中引入了上述 duck typing 的语言推断测试规则。换言之,它不关注对象的类型,而是关注对象具有的行为 (方法)。以下是 Python 术语表对其定义的阐述:
Pythonic programming style that determines an object's type by inspection of its method or attribute signature rather than by explicit relationship to some type object ("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()
orisinstance()
. Instead, it typically employs the EAFP (Easier to Ask Forgiveness than Permission) style of programming.
二、说明
鸭子类型 (duck typing) 作为程序设计中的一种 类型推断风格,适用于 大部分脚本语言 / 动态语言 (如 Python、Ruby、Perl、Julia、JavaScript 等) 和 某些静态语言 (如 Golang,通常静态类型语言在编译前便已显式指定变量类型,而 Golang 却则在编译时推断变量类型)。支持 duck typing 的语言,其 解释器/编译器 将会在解释/解析 (Parse) 或编译时推断对象类型。
鸭子测试 可以表述为:“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子”。在 duck typing 中,关注的不是对象的类型本身,而是它是如何使用的。与此同时,与 duck typing 相对应的风格是 normal typing,后者由对象类型决定了对象的特性。以下对比说明二者区别:
一方面,以 形象化的表述 为例:在使用 normal typing 的语言中,可以编写一个 “鸭子动作” 函数,它能够接受一个类型为 “鸭子” 的对象,并调用它的 “飞”、“跑” 等方法。在运行前,需要进行对象是否确实为 “鸭子” 等类型检查。相应地,在使用 duck typing 的语言中,也可以编写一个 “鸭子动作” 函数,它能够接受一个任意类型的对象,并调用它的 “飞”、“跑” 等方法。换言之,只要传入对象具有正确的 “飞”、“跑” 等方法,就都可以被函数正常接受和调用。但若这些需要被调用的方法不存在,那么将引发一个运行时错误。
另一方面,以 结合语言的表述 为例:C 属于 normal typing,在 编译阶段进行静态检查,函数定义和传参类型不一致就报错。相应地,Python 属于 duck typing,对象的类型不重要,只要对象具有类型 duck 的方法和属性,那么它就会被当做类型 duck 来使用 (因此经常能够混用类型)。Python 没有静态检查类型匹配情况,只有 运行时找不到相应属性和方法时才报错。
此外,如果只了解 Java、C++ 等静态语言,可能对鸭子类型的理解并不深刻,因为静态语言中,对象的特性取决于其父类。而动态语言则显著有别,例如 Python 的迭代器 (iterator),任何支持迭代协议 (同时实现 __iter__ 和 __next__ 方法) 的对象都可称之为迭代器,但对象本身是什么类型并不受到限制,甚至可以为任何自定义类。
三、举例
>>> class Duck:"Duck 对象具有 fly 方法 (鸭子的飞行行为) 和 run 方法 (鸭子的奔跑行为)"def fly(self):print("Duck flying")def run(self):print("Duck running")>>> class Chick:"Chick 对象具有 fly 方法 (小鸡的飞行行为) 和 run 方法 (小鸡的奔跑行为)"def fly(self):print("Chick flying")def run(self):print("Chick running")>>> class Plane:"Plane 对象具有 fly 方法 (飞机的飞行行为)" def fly(self):print("Plane flying")>>> class Fish:"Fish 对象具有 swim 方法 (鱼儿的游泳行为)"def swim(self):print("FIsh Swimming")>>> def go(entity): "令传入实例对象 entity 执行飞行和奔跑操作 (不论什么东西能飞、能跑就行)"entity.fly() # 令传入实例对象 entity 执行 fly 方法entity.run() # 令传入实例对象 entity 执行 run 方法>>> duck = Duck() # 实例化 Duck 对象
>>> chick = Chick() # 实例化 Chick 对象
>>> plane = Plane() # 实例化 Plane 对象
>>> fish = Fish() # 实例化 Fish 对象>>> go(duck) # 有 fly 和 run 方法就能正常运行, 不关心实例对象的类型是什么 (不论什么东西, 能飞和跑就行)
Duck flying
Duck running>>> go(chick) # 有 fly 和 run 方法就能正常运行, 不关心实例对象的类型是什么 (不论什么东西, 能飞和跑就行)
Chick flying
Chick running>>> go(plane) # 没有 run 方法就报错, 不关心实例对象的类型是什么 (不论什么东西, 不能跑就不行)
Plane flying
Traceback (most recent call last):File "<pyshell#20>", line 1, in <module>go(plane)File "<pyshell#13>", line 3, in goentity.run()
AttributeError: 'Plane' object has no attribute 'run'>>> go(fish) # 没有 fly 方法就报错, 不关心实例对象的类型是什么 (不论什么东西, 不能飞就不行)
Traceback (most recent call last):File "<pyshell#44>", line 1, in <module>go(fish)File "<pyshell#35>", line 2, in goentity.fly()
AttributeError: 'Fish' object has no attribute 'fly'
至于各种编程语言中的 duck typing,还可以看这其中的例子:编程语言中的 DUCK TYPING
四、不足
鸭子类型 (duck typing) 没有任何静态检查 (如类型检查、属性检查、方法签名检查等),其通常得益于 不测试方法和函数中参数的类型,而是 依赖文档、清晰的代码和测试来确保正确使用。这既是优点也是缺点,缺点是需要通过文档才能知道参数类型,为了弥补这方面的不足,Python3.6 引入了类型信息,定义变量的时候可以指定类型。此外,从静态类型语言转向动态类型语言的用户通常试图添加一些静态的 (运行前的) 类型检查,从而影响了鸭子类型的益处和可伸缩性,并约束了语言的动态特性。
鸭子类型 (duck typing) 语言的程序 可能会在运行时因不具备某种特定的方法而抛出异常 (例如上例中的 plane 没有 run 方法、fish 没有 fly 方法),形象化地举例说明:如果一只小狗 (对象) 想加入合唱团 (以对象会不会嘎嘎嘎叫的方法为检验标准),也学鸭子那么嘎嘎嘎叫,好吧,它加入了,可是加入之后,却不会像鸭子那样走路,那么,迟早要出问题的。
再举个例子:一只小老鼠被猫盯上了,情急之下,它学了狗叫,猫撤了之后,小老鼠的妈妈不无感叹的对它说:看吧,我让你学的这门儿外语多么重要啊。这虽然是个段子,但是,由于猫在思考时,使用了 "鸭子测试",它以为会叫的就是狗,会对自己产生威胁,所以撤退了,也正是因为这个错误的判断,它误失了一次进食机会。
参考文献
duck type - 简书
Python:动态语言与鸭子类型
编程语言中的 DUCK TYPING - SegmentFault 思否
duck type鸭子类型 - youxin - 博客园
到底啥是鸭子类型(duck typing)带简单例子 - 筱筱的春天 - 博客园
https://baike.baidu.com/item/鸭子类型/10845665?fr=aladdin
【Python】浅谈 鸭子类型 (Duck Typing)相关推荐
- Python编程基础:第四十九节 鸭子类型Duck Typing
第四十九节 鸭子类型Duck Typing 前言 实践 前言 本节我们一起学习一个非常有趣的知识点:鸭子类型.有这么一句话:If it walks like a duck, and it quacks ...
- duck typing java_编程语言中的鸭子类型 Duck Typing
来源 | https://segmentfault.com/a/1190000019607240 1.什么是鸭子类型(duck typing) 百度百科是这样解释的: 这是程序设计中的一种类型推断风格 ...
- 编程语言中的鸭子类型 Duck Typing
来源 | https://segmentfault.com/a/1190000019607240 1.什么是鸭子类型(duck typing) 百度百科是这样解释的: 这是程序设计中的一种类型推断风格 ...
- Python笔记 · 鸭子类型 / Duck Typing
1. 问题的由来 我初次意识到鸭子类型的存在是在学习Sklearn时,在<Hands-On Machine Learing>一书的第二章,作者提供了一个自定义的Tansformer,使用自 ...
- 鸭子类型duck typing(动态)
在程序设计中,鸭子类型(duck typing)是动态类型的一种风格.在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由当前方法和属性的集合决定.这个概念的名字来源于由Ja ...
- Python学习笔记——鸭子类型(duck typing)
前言 在实习期间,由于工作需要首次接触了Python这门语言,由于学习和使用的时间非常短,所以当时认为,作为一门解释性语言,在做Web开发方面,Python和PHP的差别不大,甚至在一些应用场景上没有 ...
- [转]编程语言中的 鸭子模型(duck typing)
在学习Python的时候发现了鸭子类型这个术语,听起来好像很有意思一样,所以把它记下来. 鸭子类型的核心概念在于一个对象的有效语义,不是继承自特定的类或者实现特定的方法,而是 由当前的属性和方法集合决 ...
- python中的鸭子类型
浅层理解 走路像鸭子,说话像鸭子,它就是鸭子 深层理解 指的是面向对中,子类不需要显示的继承某个类,只要有某个的方法和属性,那我就属于这个类 编程语言中的鸭子类型说明 假设有个鸭子类Duck类,有两个 ...
- 【python 笔记/小白快速入门python】python浅谈(一)犹抱琵琶半遮面
python浅谈(一)犹抱琵琶半遮面 继浅谈(零)初识庐山真面目[https://blog.csdn.net/HarryOtter/article/details/90519877 ] 之后,终于窥得 ...
最新文章
- 智能睡眠评估系统(包含:睡眠数据特征工程、睡眠评分、睡眠聚类、睡眠可视化分析、睡眠结论存储)
- SAP PP使用ECR去修改BOM主数据
- 让linux的防活墙也像windows一样简单易用
- xml学习总结(三)
- php 比java 快_php比java要快在哪里
- Java FilterInputStream reset()方法与示例
- 1流明等于多少lux_光通量(流明)和照度(勒克司)定义及换算关系
- python导入matplotlib模块_从NumPy导入python子模块有什么区别,matplotlib包
- 织梦dedecms怎么改模板
- LeetCode - 720 - 词典里最长的单词(longest-word-in-dictionary)
- 香港黄金配角吴孟达去世,80后程序员以轮播图来悼念达叔,达叔一路走好!
- 修复下载后已发生损坏的压缩包(.rar)文件
- 7-4 韩信点兵 (10 分)
- off-by-onedoublefree. 看雪10月ctf2017 TSRC 第四题赛后学习
- Google推荐的15条HTML 5代码军规
- 高级转录组调控分析和R语言数据可视化第十三期 (线上/线下同时开课)
- 关于英语的大小写规则
- 分享125个ASP源码,总有一款适合您
- git拉取指定分支上面的代码 提交本地分支到远程
- 劳务报酬所得税java程序计算