Python 的鸭子类型

先看一段很常见的"防御性"代码:

python 复制代码
def greet_all(names):
    if not isinstance(names, list):   # 先确认它是 list
        raise TypeError("必须是列表")
    for n in names:
        print("你好,", n)

很多从静态语言转过来的人,第一反应就是先检查类型:"传进来的必须是 list,不然不放心。"

可 Python 老手看到这段会皱眉:你凭什么非得让它是个 list? 只要它能被 for 遍历,tuple、set、甚至一个自定义对象,凭什么不能传?

这就是 Python 里最反直觉、也最舒服的一条哲学------鸭子类型(Duck Typing)。

"鸭子类型"这个名字,本身就是个比喻

它来自一句俏皮话:

如果它走起来像鸭子,叫起来像鸭子,那它就是鸭子。

翻译成代码语言就是:别关心对象"是什么",只关心它"能做什么" 。一个对象只要能调用 quack(),那不管它是真鸭子、橡皮鸭子还是机器人鸭子,对我来说就是鸭子。

静态语言的"证件" vs 动态语言的"本事"

在 Java 这类静态语言里,一个方法要收什么,得写在脸上:

java 复制代码
void makeDuckSound(Duck duck) {   // 参数类型锁死:必须是 Duck
    duck.quack();
}

你想传个"会叫的狗"进去?对不起,它没继承 Duck,编译都过不了。想让它被接受,得先让它实现某个接口或继承某个类------相当于先办张"鸭子证"。

Python 反过来了:

python 复制代码
def make_duck_sound(anything):
    anything.quack()    # 不查户口,直接看它会不会 quack

传进来的是啥我不管,你只要会 quack(),我就敢用你 。一个类只要定义了 quack 方法,它就是"鸭子",哪怕它名字叫 Dog。

好处坏处,都藏在这份"不设防"里

好处是灵活得让人上瘾 。写一个通用函数,不用为每一种类型写一份重载,也不用搞一堆抽象基类。很多 Python 的"魔法"都建立在鸭子类型上------比如 for 循环不关心你是什么,只要你实现了 __iter__;len() 不关心你是什么,只要你实现了 __len__;with 不关心你是什么,只要你实现了 __enter__ 和 __exit__(写了三十行 try...finally,Python 一个 with 就替你兜底了------别再用完才想起关文件)。

坏处是"不报错"不等于"对" 。静态语言在编译期就把"类型不对"拦下来了;鸭子类型则把检查推迟到了运行期------你传错对象,只有跑到那一行、调用那个不存在的方法时,才 AttributeError 崩掉。

所以 Python 社区演化出了两句心法:

  • LBYL(Look Before You Leap) :跳之前先看一眼------if isinstance(...),就是开头那种"防御式";
  • EAFP(Easier to Ask Forgiveness than Permission) :与其请求许可,不如事后道歉------先直接干,出错了再 except 兜着。

Python 官方偏爱的,是后者。看这段:

python 复制代码
def get_user_agent(request):
    try:
        return request.user_agent    # 直接访问,赌它有这个属性
    except AttributeError:
        return "unknown"

不检查"你是不是有 user_agent",直接取,取不到就默认。这就是鸭子类型的日常。

一份自由,配一份责任

鸭子类型给的是自由 :你可以不办任何"证件",就写出极其通用、极其简洁的代码。但它同时也把责任悄悄推给了你:因为编译器不帮你把关了,你得自己心里清楚"我期望这个对象会什么",并把边界(或异常)处理干净。

说到底,鸭子类型信的是这么一句话:能力比出身重要,行为比标签重要。

一个对象配不配得上某个角色,不该看它"登记"成了什么,而该看它"实际"能做什么。写代码是这个理,看人,不也常常是这个理么。

想系统掌握 Python 这些动态特性背后的机制,推荐 B站【408实验室】的《Python 完全自学教程》。

相关推荐
昵称画1 小时前
交接班记录电子化:三班之间的信息不漏
开发语言·数据库·人工智能·低代码·php
“AI国潮设计-小江”1 小时前
【AIGC实战】Python+SDXL批量生成“潮汕英歌舞不倒翁”IP | 角色一致性与多场景融合方案,附完整代码
开发语言·人工智能·python·prompt·aigc
传奇开心果编程1 小时前
【Rust入门练中学】第6课:结构体与方法
开发语言·rust·结构体·编程语言理论·结构体方法·编程通用语言
Linux_cy1 小时前
服务器管理工具哪个好用?我用了七八个
运维·服务器·javascript·python·ssh·面板·gmssh
MoRanzhi12031 小时前
第6篇(下)· 使用 PyQt5 实现 2048 高性能计算版:统一运行控制与跨模式安全交接
python·pyqt·进程管理·状态机·软件架构·并发控制·数据一致性
code tsunami2 小时前
【无标题】
开发语言·python
CodeGL2 小时前
10、Python基础之进程和线程
开发语言·python
TechWayfarer3 小时前
PHP漏洞被利用,怎么揪出攻击IP?
开发语言·python·tcp/ip·网络安全·php
2601_967980114 小时前
Python列表操作方法详解
python·数据类型·修改·列表操作·功能汇总
卡卡~~4 小时前
“101计划”核心课程实践教材《数据实验结构指导-C++语言版》题目集
开发语言·c++·学习·算法