不加 @functools.wraps(func) 会导致被装饰函数的 name__、__doc__、__module__、__qualname__、__annotations 等元信息丢失,变为 wrapper 函数的信息,引发调试、文档生成、类型检查及框架反射(如 FastAPI、pytest)异常。

为什么 functools.wraps 不能省略
直接说结论:不加 @functools.wraps(func) 的装饰器,会让被装饰函数的元信息(__name__、__doc__、__module__ 等)全部丢失,变成内层包装函数的信息。这在调试、文档生成、类型检查、框架反射(如 FastAPI 路由注册、pytest 参数发现)中会出问题。
functools.wraps 修复哪些具体字段
它本质是调用 update_wrapper,把原函数的关键属性复制给包装函数。默认同步以下字段:
-
__module__:避免显示为functools或装饰器所在模块 -
__name__:否则my_func.__name__变成wrapper -
__qualname__:影响嵌套函数和类方法的路径表示 -
__doc__:否则help(my_func)或 Sphinx 文档抓不到说明 -
__annotations__:类型提示丢失,mypy和 IDE 自动补全失效
不加 @wraps 的典型报错场景
这些不是语法错误,但会让工具链“认不出”你的函数:
- FastAPI 报
TypeError: Unable to extract signature for ...—— 因为inspect.signature()拿不到原函数签名 - pytest 发现不了测试函数:若用
@pytest.mark.parametrize套在没@wraps的装饰器上,可能跳过执行 -
help(my_decorated_func)显示空文档或Help on function wrapper in module ... - 日志里记录函数名变成
wrapper,排查时无法定位真实逻辑
一个最小可验证示例
from functools import wrapsdef my_decorator(func): def wrapper(*args, *kwargs): print("before") result = func(args, **kwargs) print("after") return result
忘记加 @wraps(func) → 元信息全丢
return wrapper@my_decorator def greet(name: str) -> str: """Say hello to someone.""" return f"Hello, {name}!"
print(greet.name) # 输出 'wrapper',不是 'greet' print(greet.doc) # 输出 None print(greet.annotations) # 输出 {},不是 {'name':
, 'return': } 只需在
def wrapper后加一行@wraps(func),所有字段立刻恢复。这个细节小,但一旦漏掉,在协作或集成时容易卡住别人——尤其是当函数要被其他库自动扫描时,它不会报错,只会静默失效。立即学习“Python免费学习笔记(深入)”;










