Python 里的“鸭子类型”(Duck Typing)

一句话:只要一个对象“像鸭子一样叫、像鸭子一样走”,就把它当成鸭子用——关注行为(拥有的方法/属性),不关心它的具体类型或继承关系。

核心要点
• 结构/行为决定可用性:函数只依赖“需要的方法名/属性名”,而非类名。
• 多态更松弛:比“必须继承某接口/基类”的名义类型(nominal typing)更灵活。
• 常配套 EAFP(Easier to Ask Forgiveness than Permission):先用,出错再处理。

最小示例:只要能 .write() 就能当“可写对象”

def dump_text(text, sink):
    # 我只需要 sink 有 write(str) 方法,至于它是文件、socket 还是内存缓冲都无所谓
    sink.write(text)

# 用真实文件
with open("out.txt", "w", encoding="utf-8") as f:
    dump_text("hello\n", f)

# 用内存对象
from io import StringIO
buf = StringIO()
dump_text("world\n", buf)

EAFP vs LBYL

EAFP(推荐):不提前查类型,直接调用,异常兜底。

def send_greeting(ch):
    try:
        ch.send("hi")     # 只要有 send 方法就行
    except AttributeError as e:
        raise TypeError("需要带有 send(str) 方法的对象") from e

LBYL(Look Before You Leap):

def send_greeting(ch):
    if hasattr(ch, "send"):
        ch.send("hi")
    else:
        raise TypeError("需要 send 方法")

在并发/动态场景下,EAFP 更稳(避免检查与调用之间对象被改变的竞态)。

与静态类型配合:typing.Protocol(结构化类型)

鸭子类型很自由,但缺少编译期校验。可用 Protocol 保留“按行为编程”的同时让 mypy/pyright 做静态检查。
from typing import Protocol

class Writer(Protocol):
    def write(self, s: str) -> int: ...

def dump_text(text: str, sink: Writer) -> None:
    sink.write(text)
# 任何实现了 .write(str)->int 的类型,都被视为 Writer(无需继承)

典型应用
• “文件样”对象:.read()/.write()/.flush()
• 可迭代对象:实现 iterlen+getitem
• 路径样对象:实现 fspath(许多标准库 API 都接受)
• 你自己的“模型样对象”:只要有 .predict()/.fit() 就能参与流水线

def evaluate(model, X):
    # 只要求有 predict 方法
    y = model.predict(X)
    ...

优缺点速览

优点:低耦合、可测试性强、易替身(mock)、更符合“面向接口而非实现”。
风险:错拼方法名/行为不符合时,错误在运行期才暴露;为此可用:
• 清晰文档/约定(说明需要哪些方法)
• Protocol 做静态检查
• 运行期用 EAFP 给出友好错误信息

一句收尾:在 Python 里,鸭子类型让你“按能力而非血统编程”;配上 Protocol 与 EAFP,就既灵活又靠谱。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MonkeyKing.sun

对你有帮助的话,可以打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值