必须使用@wraps(func)装饰器,否则路由注册、pytest发现、文档生成、类型检查等功能均会因__name__变为'wrapper'而失效。

Flask/FastAPI 路由注册时找不到函数名
Flask 和 FastAPI 在注册路由时,会读取被装饰函数的 __name__ 来生成默认端点名(endpoint)或用于调试日志。如果装饰器没用 @wraps(func),__name__ 就是 'wrapper',不是原函数名。
常见错误现象:
- FastAPI 报错
ValueError: Duplicate endpoint name—— 多个@app.get装饰后都叫wrapper,框架认为是重复注册 - Flask 启动时报
AssertionError: View function mapping is overwriting an existing endpoint,原因同上 -
app.url_for('wrapper')失败,因为实际 endpoint 名是say_hello,但你查的是wrapper
pytest 自动发现测试函数失败
pytest 默认只收集名称以 test_ 开头、且 __name__ 未被污染的函数。如果装饰器返回的 wrapper.__name__ == 'wrapper',pytest 就不会把它当测试函数。
使用场景:
- 你写了
@retry(3)包裹一个test_api_timeout,但运行pytest时它根本没被执行 -
pytest --collect-only列出的函数名是wrapper,而不是你期望的test_api_timeout - 即使加了
@pytest.mark.asyncio,只要__name__不对,pytest 的收集器就跳过它
help() 和 sphinx 文档生成完全失效
help()、pydoc、sphinx 的 autofunction 都依赖 __name__ 和 __doc__ 定位原始函数信息。一旦 __name__ 变成 wrapper,这些工具就查不到源函数的模块路径和文档。
参数差异与影响:
- 没加
@wraps:调用help(fetch_data)显示的是wrapper(*args, **kwargs),没有参数说明,也没有原始 docstring - 加了
@wraps(func):help(fetch_data)正确显示fetch_data(url: str) -> dict和完整文档 - sphinx 构建时若遇到
__name__ == 'wrapper',会跳过该函数,导致 API 文档缺失
inspect.signature() 获取错误签名
现代 Python 类型检查、IDE 补全、FastAPI 参数解析都靠 inspect.signature(func) 读取形参列表。而 signature() 内部会通过 func.__wrapped__(由 @wraps 自动设置)回溯到原始函数;如果没设 __wrapped__,它就只能分析 wrapper(*args, **kwargs) 这个万能签名。
容易踩的坑:
- FastAPI 无法自动提取
def get_user(id: int)中的id: int,转而把整个请求体当**kwargs处理 - PyCharm 提示 “No parameter information available”,补全失效
-
inspect.signature(wrapper)返回(*args, **kwargs),而非真实参数名和注解
__name__ 看起来不对,而是它背后连带的 __doc__、__module__、__annotations__ 和 __wrapped__ 全都断链了——这些属性在框架底层是硬依赖,不是“可有可无”的展示信息。Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











