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()
都使用的是不同的对象(数字、列表和字符串),并且它们在继承关系中没有联系。只要输入对象支持+
和*
方法,操作就能成功。【Python中的鸭子类型】执行后输出:
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中的while...else方法
- python中利用break 和continue退出for循环
- Python中的for循环语法和示例
- R语言用关联规则和聚类模型挖掘处方数据探索药物配伍中的规律
- python中使用马尔可夫决策过程(MDP)动态编程来解决最短路径强化学习问题
- Java9新特性中的模块化详解
- Python使用Keras|Python使用Keras OCR实现从图像中删除文本
- 一文教会你用Python获取网页指定内容
- leetcode|Leetcode83(力扣83)(删除排序链表中的重复元素)