实现一个自定义的ducktyping
1 简介
本文实现直接运行的 Python 示例代码,用最少逻辑实现类似 Flask/Django 中最典型的 duck typing 行为。

代码全部可独立运行,无需安装 Flask/Django,全部是“简化版模型”。
2 示例 1: make_response 对多种返回值的处理
展示 Flask 如何靠 duck typing 接受:字符串、字典、可调用对象、自定义 Response 类
-
可运行代码
class SimpleResponse: def __init__(self, data, status=200): self.data = data self.status = status def __repr__(self): return f"<Response {self.status}: {self.data}>" @classmethod def force_type(cls, obj): # 模拟 Flask 的 force_type,尝试把对象强转为 Response return cls(str(obj)) def make_response(rv): # 模仿 Flask:tuple = (body, status) if isinstance(rv, tuple): body, status = rv return SimpleResponse(body, status) # Response 对象 if isinstance(rv, SimpleResponse): return rv # 可调用 → 视作 WSGI 应用 if callable(rv): return SimpleResponse(rv()) # dict → 自动转换为 JSON 字符串 if isinstance(rv, dict): return SimpleResponse(f"json:{rv}") # str → 直接构造响应 if isinstance(rv, str): return SimpleResponse(rv) # 其他对象 → 强转 return SimpleResponse.force_type(rv) -
测试 ----------
print(make_response(“hello”))
print(make_response({“msg”: “ok”}))
print(make_response((“not found”, 404)))
print(make_response(lambda: “callable result”))
print(make_response(12345)) # force_type 转 str
- 输出示例
<Response 200: hello>
<Response 200: json:{‘msg’: ‘ok’}>
<Response 404: not found>
<Response 200: callable result>
<Response 200: 12345>
Duck typing 关键点
可调用对象就当 WSGI app
dict 就当 JSON 内容
任意对象可通过 force_type() 转换
3 示例 2:复刻 Django 中间件“只要可调用就能用”
Django 中间件核心逻辑是:
只要对象可调用(callable),就能被当作中间件使用。
- 可运行代码
简化版 Django 中的 middleware 链构建
def load_middleware(middlewares, get_response):
chain = get_response
for mw_class in reversed(middlewares):
mw_instance = mw_class(chain)
if not callable(mw_instance):
raise TypeError("Middleware must be callable")
chain = mw_instance
return chain
- 模拟 request handler
def get_response(request):
return f"Final response: {request}"
-
两种不同类型的中间件 ---------
class ClassMiddleware: def __init__(self, get_response): self.get_response = get_response def __call__(self, request): print("ClassMiddleware processing") return self.get_response(request) def function_middleware(get_response): # 返回一个可调用对象就行 def inner(request): print("FunctionMiddleware processing") return get_response(request) return inner -
测试 ----------
middlewares = [ClassMiddleware, function_middleware]
handler = load_middleware(middlewares, get_response)print(handler(“REQ”))
输出示例
ClassMiddleware processing
FunctionMiddleware processing
Final response: REQ
- Duck typing 实现点
中间件可以是类(实现了 call)
也可以是函数(返回可调用)
Django 不检查继承结构,只检查“能不能调用”
4 示例 3:复刻 Django QuerySet:
关键点:实现 iterable(像 list 却不是 list)
Django 的 QuerySet 并不是 list,但 QuerySet:
能被 for 遍历 → 因为实现了 iter
能被 len 调用 → 通过 len
能被切片 → getitem
-
可运行代码
class MiniQuerySet: def __init__(self, data_loader): self._data_loader = data_loader self._cache = None def _fetch_all(self): if self._cache is None: print("Fetching data from database...") self._cache = list(self._data_loader()) def __iter__(self): self._fetch_all() return iter(self._cache) def __len__(self): self._fetch_all() return len(self._cache) def __getitem__(self, index): self._fetch_all() return self._cache[index] -
测试 ----------
def db_loader():
return [1, 2, 3, 4]
qs = MiniQuerySet(db_loader)
for item in qs:
print(item)
print(“Length:”, len(qs))
print(“First item:”, qs[0])
- 输出示例
Fetching data from database…
1
2
3
4
Length: 4
First item: 1
- Duck typing 实现点
QuerySet 实现 iterable protocol → 可 for 遍历
实现 getitem → 可切片
实现 len → 支持 len()
无须继承 list,只需“像 list 一样行为”。
6 小结:
三类 duck typing 行为自定义成功
行为 框架 示例 Duck typing 核心
多类型响应自动转换 Flask make_response 示例 “能当响应用即可”
全可调用中间件 Django middleware 示例 “能 call() 就是中间件”
QuerySet 像列表 Django iterable 示例 “实现迭代行为就能当集合”
- 点赞
- 收藏
- 关注作者
评论(0)