不加 @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 的典型报错场景
这些不是语法错误,但会让工具链“认不出”你的函数:
西安网上购物网店系统的主要亮点:(1)商品的分类更加细化和明朗,可以三级分类,价格可以多层次\多级别,按照后台设置的,吸引会员加入。(2)会员和非会员购物并存,订单直接支付和会员帐户支付并存,电话支付与网上支付多种支付方式。(3)自定义商品扩展属性,多种扩展属性定义模式,强大的商品管理功能,多重分类功能(4)灵活的会员积分系统,灵活的会员权限控制,模版丰富多彩,模版代码分离,方便修改模版(5)支付
- 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免费学习笔记(深入)”;









