说它是谁就是谁—Python语言中的鸭子类型

鸭子类型(Duck Typing)是动态类型语言中的一种类型推断风格,尤其在Python语言中得到了广泛的应用。它的核心思想是:“如果它走起路来像鸭子,叫起来像鸭子,那么它就是鸭子”。这句话的意思是,我们不关心对象的类型是什么,而只关心对象的行为。只要对象具有所需的方法和属性,它就可以被视为具有所需的类型。

鸭子表情包|插画|其他插画|李小障YJ - 原创作品 - 站酷 (ZCOOL)

01 /  原理

一个对象的类型不是由其继承的类或实现的接口来决定的,而是由其行为(即对象的方法集)来决定的。如果一个对象能够响应某个特定类型的请求,那么就可以将其视为该类型的对象。当我们需要判断一个对象是否属于某个类型时,我们不需要查看其类型声明,而是检查它是否具有该类型对象所应该具有的方法。如果对象具有这些方法,并且这些方法的行为符合预期,那么我们就可以将其视为该类型的对象。

02 /  应用场景

  • 迭代器协议:在Python中,任何具有__iter__和__next__方法的对象都可称之为迭代器,但对象本身是什么类型不受限制,可以自定义为任何类。

  • 上下文管理器协议:通过实现__enter__和__exit__方法,任何对象都可以被用作with语句的上下文管理器。

  • 依赖注入:在设计模块化和可重用的代码时,可以通过依赖注入的方式传递对象,只要这些对象实现了所需的接口,而不需要关心它们的具体类型。

03 /  Quick Start

下面是一个简单的Python代码示例,展示了鸭子类型的概念:

class Duck:def quack(self):print("Quack!")def fly(self):print("Flying...")
​
class Person:def quack(self):print("I'm quacking like a duck!")def fly(self):print("I can't fly!")
​
class Car:def quack(self):print("Honk honk!")  # 模拟鸭子的叫声
​
def make_quack(duck_like_object):if hasattr(duck_like_object, 'quack') and callable(duck_like_object.quack):duck_like_object.quack()else:print("Error: This object cannot quack!")
​
def make_fly(duck_like_object):if hasattr(duck_like_object, 'fly') and callable(duck_like_object.fly):duck_like_object.fly()else:print("Error: This object cannot fly!")
​
# 创建实例
duck = Duck()
person = Person()
car = Car()
​
# 测试代码
make_quack(duck)  # 输出: Quack!
make_quack(person)  # 输出: I'm quacking like a duck!
make_quack(car)    # 输出: Honk honk!
​
make_fly(duck)     # 输出: Flying...
make_fly(person)   # 输出: I can't fly!
make_fly(car)      # 输出: Error: This object cannot fly!

在这个例子中,我们定义了三个类:Duck、Person和Car。Duck和Person类都有quack和fly方法,而Car类只有quack方法,模拟汽车按喇叭的声音。我们定义了两个函数make_quack和make_fly,它们接受一个对象作为参数,并检查这个对象是否有相应的方法。如果有,就调用这个方法;如果没有,就打印一条错误信息。

这个例子展示了鸭子类型的核心思想:我们不关心对象的类型,只关心它是否有我们需要的方法。这样,即使是Car类的对象,只要它有quack方法,就可以被make_quack函数接受。而对于make_fly函数,由于Car类没有fly方法,所以会打印错误信息。这正是鸭子类型的特点:如果它表现得像鸭子,我们就把它当作鸭子对待。

注意事项

  • 运行时错误:由于鸭子类型推迟了类型检查到运行时,某些类型相关的错误只有在代码实际运行时才会被发现。因此,良好的测试变得尤为重要。

  • 代码可读性:对于不熟悉鸭子类型的新手或不熟悉代码库的开发者来说,鸭子类型可能会导致代码可读性降低。因此,适当的注释和文档说明变得更加重要。

  • 缺乏明确的契约:在使用鸭子类型时,没有明确的接口契约,这可能导致开发者依赖于文档或查看源代码来了解对象的行为,这可能会增加理解和维护代码的难度

  • 调试困难:由于没有静态类型检查,当在运行时出现错误时,调试可能会变得更加困难。在编译时无法捕获到类型相关的错误,需要在运行时通过测试和调试来发现

  • 可能的运行时错误:由于鸭子类型允许对象在运行时决定其行为,如果对象的行为不符合预期,可能会导致运行时错误,而不是在编译时捕获到错误。

  • 难以进行静态分析:鸭子类型的灵活性使得在静态分析工具中难以确定对象的确切类型和行为。这可能影响一些工具的有效性,如自动化的代码审查工具或IDE的智能提示

  • 接口的明确性:在设计函数或方法时,应该清晰地定义所需对象的接口(即所需的方法和属性),即使不使用显式的类型声明。这有助于其他开发者理解和使用你的代码

  • 使用类型提示:在Python 3.6及以上版本中,可以使用类型提示来增加代码的可读性和IDE的支持。虽然这不会强制类型检查,但它提供了额外的文档和IDE自动完成功能

  • 结合使用抽象基类(ABCs)和协议(Protocols):对于更复杂的代码库,可以使用抽象基类或Python 3.8及以上版本中的协议来定义对象必须实现的接口,这样可以在保持鸭子类型灵活性的同时,提供更多的类型安全保障

04 / 实战案例

电子商务平台的商品推荐系统。在这个系统中,我们可能有多种不同类型的推荐器,比如基于用户的推荐器、基于物品的推荐器、基于协同过滤的推荐器等。这些推荐器的共同点是它们都能提供一个recommend方法,该方法接受用户ID作为参数,并返回一组推荐商品。

class UserBasedRecommender:def recommend(self, user_id):# 实现基于用户的推荐逻辑pass
​
class ItemBasedRecommender:def recommend(self, user_id):# 实现基于物品的推荐逻辑pass
​
class CollaborativeFilteringRecommender:def recommend(self, user_id):# 实现协同过滤推荐逻辑pass
​
def display_recommendations(recommender, user_id):recommendations = recommender.recommend(user_id)print(f"Recommendations for user {user_id}: {recommendations}")
​
recommender1 = UserBasedRecommender()
recommender2 = ItemBasedRecommender()
recommender3 = CollaborativeFilteringRecommender()
​
display_recommendations(recommender1, "user123")
display_recommendations(recommender2, "user123")
display_recommendations(recommender3, "user123")

在这个例子中,三个类都没有继承自同一个基类,但它们都有recommend方法。因此,我们可以将它们的对象传递给display_recommendations函数,而不需要关心推荐器的具体类型。这样,我们就可以根据需要灵活地添加或替换推荐器,而不影响其他部分的代码。这种设计提高了代码的灵活性和可扩展性,同时也降低了各个推荐器之间的耦合度。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/58098.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python_httpstat库

Python httpstat是一个基于Python的命令行工具,用于测量HTTP请求的性能和状态信息。它能够向目标服务器发送HTTP请求,并显示详细的统计信息,包括DNS解析时间、建立连接时间、TLS/SSL握手时间、首字节时间、总时间等。这些信息对于排查网络问题…

详解varint,zigzag编码, 以及在Go标准库中的实现

文章目录 为啥需要varint编码为啥需要zigzag编码varint编码解码 zigzag编码解码 局限性 为啥需要varint编码 当我们用定长数字类型int32来表示整数时,为了传输一个整数1,我们需要传输00000000 00000000 00000000 00000001 32 个 bits,而有价…

SQLite3库增删改查实现数据管理

1. SQLite3简介 SQLite3是一个轻量级的、嵌入式的关系型数据库管理系统,在保存测序数据或结果等时可使用,简单高效,并且有无需服务器、单文件存储数据、支持标准SQL、支持跨平台等优势。 本文以Sqlite3数据库为基础,创建代码示例…

tomcat基本配置

目录 1.java容器简介介绍 2.部署tomcat 2.1上传jdk 2.2创建一个软连接 2.3配置环境变量 2.4读取环境文件并且查看java版本 2.5检查jdk tomcat信息 2.6启动tomcat 2.7检测 3.tomcat 目录结构 3.1总体目录 3.2 bin目录 3.3conf 3.4 logs日志 4.运行代码 4.…

如何确保电子商务网站服务器的正常运行时间

对于电商网站而言,服务器的正常运行时间至关重要。网站宕机会直接影响销售额、客户体验以及品牌声誉。本文将详细探讨如何监控并保障服务器的正常运行时间,确保您的电商网站始终保持在线状态, 为什么监控正常运行时间很重要? 减…

【Oracle实验】字段为空的,无法通过排除判断

Oracle相关文档,希望互相学习,共同进步 风123456789~-CSDN博客 1.场景描述 需求:查询不是某个机构的数据。 同事SQL:where substr(bank_code,1,9) not in(014009001); 看SQL似乎没什么问题,分析…

【modbus协议】libmodbus库移植基于linux平台

文章目录 下载库函数源码编译路径添加libmodbus 源码分析核心数据结构常用接口函数 开发 TCP Server 端开发TCP Client 端 下载库函数源码 编译路径添加 libmodbus 源码分析 核心数据结构 modbus_t结构体: 这是 libmodbus 的核心数据结构,代表一个 Mod…

OSPF特殊区域及其他特性

不用的链路这状态信息没必要一直保存,要不路由器承受不了。用OSPF 特殊区域解决 1. Stub区域和Totally Stub区域 R1作为ASBR引入多个外部网段,如果Area 2是普通区域,则R3将向该区域注入5类和4类LSA。 当把Area 2配置为Stub区域后&#xff1a…

node升级package.json中的版本

由于项目使用时间过老,升级对应包版本,可以使用新功能 1.使用npm-check-updates这个工具,先全局安装 npm install -g npm-check-updates2.检查package.json中dependencies的最新版本 ncu3.更新dependencies到新版本 ncu -u也是一样的 npx…

探索Python安全字符串处理的奥秘:MarkupSafe库揭秘

文章目录 探索Python安全字符串处理的奥秘:MarkupSafe库揭秘第一部分:背景介绍第二部分:MarkupSafe是什么?第三部分:如何安装MarkupSafe?第四部分:MarkupSafe的简单使用方法1. 使用escape函数2.…

机器视觉运动控制一体机在DELTA并联机械手视觉上下料应用

市场应用背景 DELTA并联机械手是由三个相同的支链所组成,每个支链包含一个转动关节和一个移动关节,具有结构紧凑、占地面积小、高速高灵活性等特点,可在有限的空间内进行高效的作业,广泛应用于柔性上下料、包装、分拣、装配等需要…

【C++】类和对象(二):this指针

大家好,我是苏貝,本篇博客带大家了解C的this指针,如果你觉得我写的还不错的话,可以给我一个赞👍吗,感谢❤️ 目录 1 this指针的引出2 this指针的特性 1 this指针的引出 我们先来定义一个日期类Date 问&am…

华为原生鸿蒙操作系统的发布有何重大意义和影响:

#1024程序员节 | 征文# 一、华为原生鸿蒙操作系统的发布对中国的意义可以从多个层面进行分析: 1. 技术自主创新 鸿蒙操作系统的推出标志着中国在操作系统领域的自主创新能力的提升。过去,中国在高端操作系统方面依赖于外国技术,鸿蒙的发布…

开发涉及的安全规范整理

文章目录 前言安全场景与措施API调用方式鉴权参数校验日志打印数据保存加密 总结 前言 这篇文章我们来整理下写代码和方案设计中的安全规范问题,内容偏服务端,即使是入门的新人,如果你对安全有所了解会让成熟规范的团队对你高看一眼。安全经常…

用HTML构建酷炫的文件上传下载界面

1. 基础HTML结构 首先&#xff0c;我们构建一个基本的HTML结构&#xff0c;包括一个表单用于文件上传&#xff0c;以及一个列表用于展示已上传文件&#xff1a; HTML <!DOCTYPE html> <html> <head><title>酷炫文件上传下载</title><link …

健康养生的重要性

养生之道&#xff0c;健康相随 在快节奏的现代生活中&#xff0c;养生健康已成为我们不可忽视的话题。随着生活水平的提高&#xff0c;人们越来越注重身体的保养与健康的维护。那么&#xff0c;如何才能做到养生健康&#xff0c;让身体与心灵都得到滋养呢&#xff1f; 首先&a…

鱼跃医疗助力退役军人事务部“高原情暖老兵项目”

10月17日-22日&#xff0c;在退役军人事务部指导下&#xff0c;中国老龄事业发展基金会联合腾讯SSV时光实验室、腾讯天籁实验室等机构发起的“情暖老兵&#xff0c;守望相助—老兵听力关怀计划”项目走进西藏&#xff0c;为退伍老兵提供听力健康筛查服务。西藏鱼跃医疗投资有限…

fastGpt

参考本地部署FastGPT使用在线大语言模型 1 rockylinx 1 ollama安装 在rockylinux中安装的&#xff0c;ollama由1.5G&#xff0c;还是比较大&#xff0c;所有采用在windows下下载&#xff0c;然后安装的方式&#xff0c;linux安装 tar -C /usr -xzf ollama-linux-amd64.tgz #…

U-net医学分割网络——学习笔记

《U-Net: Convolutional Networks for Biomedical Image Segmentation》 一、提出背景 U-Net 的提出是为了解决生物医学图像分割的几个关键问题&#xff1a;需要像素级的精确分割、标注数据稀缺、滑动窗口方法效率低以及多尺度特征融合的需求。U-Net 通过对称的 U 型全卷积结…

Redis+Lua限流的四种算法

1. 固定窗口&#xff08;Fixed Window&#xff09; 原理&#xff1a; 固定窗口算法将时间划分为固定的时间段&#xff08;窗口&#xff09;&#xff0c;比如 1 秒、1 分钟等。在每个时间段内&#xff0c;允许最多一定数量的请求。如果请求超出配额&#xff0c;则拒绝。 优点…