了解接口类型duck typing
1 简介
本文简介duck typing类型, 一个简洁、可直接运行的 Python3 示例,展示“鸭子类型”(duck typing) 如何让代码灵活 + 简洁;最后说明 Flask 与 Django 中有哪些典型地方使用了这一思想。

2 Python 鸭子类型示例
无需关心对象的真实类型,这就是鸭子类型核心思想:
“If it walks like a duck and quacks like a duck, it's a duck.”
只要对象实现了所需的行为(方法/属性),就可以被当作某类对象使用,不关心其实际类型或继承体系。
- 示例 1:
同一函数可以处理不同类型的对象
class FileLike:
def read(self):
return "I behave like a file"
class NetworkStream:
def read(self):
return "I behave like a network stream"
def process(stream):
# 不关心 stream 是否是 file stream / network stream / memory buffer
print("Reading:", stream.read())
不同对象,只要有 read() 方法,就都能用
process(FileLike())
process(NetworkStream())
- 优点
无需定义共同接口(无须 Java 式接口/继承)
函数只要求“对象能干什么”,而非“对象是什么类型”
- 示例 2:
支持 len() 的对象不必继承任何类
class MyCollection:
def __init__(self, items):
self.items = items
def __len__(self):
return len(self.items)
调用实例
c = MyCollection([1,2,3])
print(len(c))
len() 不要求继承,它只需要对象实现 len。
这就是 Python 的“结构化行为接口”。
3、Flask 中的鸭子类型典型应用
Flask 是一个非常典型、充分利用鸭子类型的框架:
-
- WSGI request/response 对象可插拔
Flask 的视图函数既可以返回:
字符串
字典
tuple
Response 对象
等
Flask 内部通过 duck typing 把返回值自动转换成 Response:
@app.route("/")
def index():
return {"msg": "Hello"} # Flask 会自动 jsonify
Flask 内部逻辑类似:
def make_response(rv):
if isinstance(rv, Response):
return rv
elif isinstance(rv, dict):
return jsonify(rv)
elif isinstance(rv, str):
return Response(rv)
你只返回“能像响应一样用”的内容就行。
-
- request 对象可使用 file-like object
上传文件获得的是 FileStorage,它实现了 .read(),可像文件一样使用:
f = request.files["file"]
content = f.read() # 像文件一样
你无需关心它不是 open() 打开的文件。
这是典型 duck typing。
4、Django 中的duck typing类型典型应用
虽然 Django 更“重量级”,但同样大量使用 duck typing:
-
- 中间件(Middleware)链不要求特定类型
只要对象实现 call(request),即可作为中间件。
class MyMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
# request 可以是任何拥有必要属性的对象
return self.get_response(request)
Django 不要求中间件继承某个基类。
-
- Django ORM 的 QuerySet 支持迭代协议
你可以像列表一样遍历 QuerySet:
for user in User.objects.all():
print(user)
因为 QuerySet 实现了 iter —— 不需要继承 list。
-
- 文件存储后端:只要求类似文件的行为
Django Storage backend 只要求对象提供:
.open()
.save()
.read()
.write()
你可以实现自己的存储:
class MyStorage:
def save(self, name, content):
# content 只要有 read() 方法即可
data = content.read()
完全基于行为判断,不需继承。
5 小结
Python、Flask、Django 都依赖鸭子类型,通过“看行为不看类型”实现了灵活、简洁、可插拔的设计。
框架 使用duck typing类型的地方 好处
Flask Response 接受多种返回值 / 上传文件像文件对象 / request 对象可替换 极度灵活、易扩展
Django Middleware、QuerySet、Storage Backend 插件式的可插拔设计,更可维护
- 点赞
- 收藏
- 关注作者
评论(0)