functools.wraps用于修复装饰后函数的元信息,避免__name__、__doc__等属性丢失;不加会导致help()显示wrapper、函数名变为'wrapper'、签名获取失败及框架注册异常。

functools.wraps 用来修复被装饰函数的元信息
不加 functools.wraps,装饰器会“吃掉”原函数的 __name__、__doc__、__module__ 等属性,导致调试、文档生成、IDE跳转等功能异常。它不是让装饰器“生效”,而是让装饰后的函数看起来还是原来的函数。
不加 wraps 会发生什么
典型表现是:help() 显示的是内层闭包函数(比如 wrapper)的信息,而不是被装饰的函数;func.__name__ 变成 'wrapper';用 inspect.signature() 获取参数签名失败;某些框架(如 Flask、Click)依赖函数名做路由或命令注册,会出错。
- 错误现象示例:
def my_decorator(func): def wrapper(*args, **kwargs): return func(*args, **kwargs) return wrapper@my_decorator def say_hello(name: str) -> str: """Say hello to someone.""" return f"Hello, {name}"
print(say_hello.name) # 输出:wrapper(不是 say_hello) print(say_hello.doc) # 输出:None(不是 "Say hello to someone.")
加 wraps 的标准写法
functools.wraps 接收原始函数作为参数,返回一个修饰器,用于装饰内部的 wrapper 函数。它本质是批量复制 __name__、__doc__、__annotations__、__module__ 等关键属性。
- 必须用在
wrapper函数定义上方,不能漏掉括号:@functools.wraps(func) - 不能写成
@functools.wraps(不带括号),否则报TypeError: wraps() missing 1 required argument - 如果装饰器本身带参数(即三层嵌套),
wraps仍作用于最内层的wrapper
import functoolsdef my_decorator(func): @functools.wraps(func) # ← 关键一行 def wrapper(*args, *kwargs): print("Before call") result = func(args, **kwargs) print("After call") return result return wrapper
@my_decorator def say_hello(name: str) -> str: """Say hello to someone.""" return f"Hello, {name}"
print(say_hello.name) # 输出:say_hello print(say_hello.doc) # 输出:"Say hello to someone." print(say_hello.annotations) # 输出:{'name':
, 'return': }
为什么 wraps 不是自动做的
Python 装饰器机制本身只是语法糖(@dec 等价于 f = dec(f)),语言不干涉你返回什么对象。functools.wraps 是一种约定俗成的“礼貌行为”,但不是强制规范。有些场景反而要故意隐藏原函数信息(比如权限拦截器不想暴露真实接口名),这时候就不该用 wraps。
大小仅1兆左右 ,足够轻便的商城系统; 易部署,上传空间即可用,安全,稳定; 容易操作,登陆后台就可设置装饰网站; 并且使用异步技术处理网站数据,表现更具美感。 前台呈现页面,兼容主流浏览器,DIV+CSS页面设计; 如果您有一定的网页设计基础,还可以进行简易的样式修改,二次开发, 发布新样式,调整网站结构,只需修改css目录中的css.css文件即可。 商城网站完全独立,网站源码随时可供您下载
立即学习“Python免费学习笔记(深入)”;
容易忽略的一点:如果装饰器中修改了 __annotations__ 或动态加了 __dict__ 属性,wraps 不会同步这些改动——它只复制默认的可读元信息。需要额外处理时得手动赋值。









