鸭子类型 (Duck Typing)
鸭子类型按行为能力而非名义类型协作;在 Python 中与特殊方法、Protocol 静态检查形成互补。
#concept
#evergreen
#dev
#python
#javascript
#python
[!info] related notes
鸭子类型 (Duck Typing)
这个概念为什么出现
框架与库常说:“给我一个 file-like / iterable / awaitable 就行”。调用方不关心它是不是某个基类的子类,只关心能不能协作。这就是鸭子类型:
若走起来像鸭子、叫起来像鸭子,就当鸭子用。
[!abstract] 一句话理解 鸭子类型以运行时行为能力决定能否协作,而不是以名义继承身份;Python 用协议与特殊方法把它变成语言习惯。
最小可运行示例
先把示例放进业务场景,再看代码:
场景:导出服务接受任何“能提供只读行迭代”的来源
# duck_typing_export.py
# 业务意图:export_lines 不要求具体类,只要可迭代文本行。
# 教学点:
# - 面向协议而非基类;
# - list 与自定义对象都能协作;
# - 缺少协议则运行时失败。
from collections.abc import Iterable, Iterator
def export_lines(lines: Iterable[str]) -> str:
# 业务:把多行正文合并为导出文本。
return "\n".join(line.rstrip("\n") for line in lines)
class TicketLog:
def __init__(self, rows: list[str]) -> None:
self._rows = rows
def __iter__(self) -> Iterator[str]:
return iter(self._rows)
def main() -> None:
print(export_lines(["a", "b"]))
print(export_lines(TicketLog(["t1", "t2"])))
if __name__ == "__main__":
main()
建议运行:
python duck_typing_export.py
期望输出:
a
b
t1
t2
结合场景再看三个关注点
- Iterable[str] 注解表达静态契约,不会在运行时自动验证每个元素是 str。\
- 自定义类实现返回迭代器的 iter,无需继承 Iterable;仍需保证产出符合业务约定的文本行。\
- 静态检查可用
Protocol提前抓缺口(见专篇)。
核心概念与准确模型
| 维度 | 鸭子类型 | 名义类型 |
|---|---|---|
| 判断 | 行为/结构 | 声明的继承/实现 |
| 时刻 | 使用行为时体现,类型检查器可提前辅助 | 可在静态检查或运行时身份检查中体现 |
| Python | 协议、dunder | ABCs 可名义可虚拟 |
Python 中的落点:
- 特殊方法协议(容器、上下文、异步)
collections.abctyping.Protocol(静态结构类型)
边界情况与反直觉行为
- 错误发现偏晚:缺方法到调用才炸。
- 同名不同义:都有
read但语义不同。 - 过度鸭子让可读性下降——公开 API 仍要文档化协议。
- hasattr/callable 只能检查有限的形状,不能证明签名、返回值、异常或副作用符合协议;runtime_checkable Protocol 也不验证完整行为。
- Python 的 iter 还支持旧式 getitem 序列协议;运行时可迭代不等于一定通过 isinstance(x, Iterable) 或静态 Iterable 类型检查。\
常见误区
[!warning] 常见误区:动态语言所以不用类型 错误理解:鸭子类型排斥标注。
正确模型:运行时鸭子 + 静态 Protocol/注解可并存。
工程实践
- 文档写清最小协议(“需要
__iter__产出 str”)。 - 边界可检查关键方法,但真正契约仍需按使用方式测试;不能把方法同名当作语义相同。\
- 公共库优先小协议,避免强迫继承框架基类。
本节总结
鸭子类型是 Python 协作的默认文化。用协议思考,用特殊方法实现,用 Protocol/测试加固。
自测题
- 鸭子类型与
isinstance强制基类有何不同? - 如何降低“用时才发现缺方法”的风险?
参考答案
- 鸭子类型按需要的行为协作;强制某具体基类通常按继承身份筛选。但 isinstance 也可由 ABC 的虚拟注册/结构钩子或 runtime_checkable Protocol 扩展,不总是纯名义判断。\
- Protocol/类型检查、契约测试、文档化最小方法集。
延伸阅读与资料来源
| 资料 | 类型 | 支撑内容 |
|---|---|---|
| Glossary – duck-typing | 术语 | 官方定义 |
| typing.Protocol | 文档 | 静态结构类型 |