直接装饰函数会丢失__name__和__doc__,因为装饰器本质是用新函数(如wrapper)替换原函数,而新函数的元数据默认来自自身定义,而非原函数;functools.wraps(func)需加括号调用,它自动复制__module__、__name__、__qualname__、__doc__、__annotations__等关键属性,确保help()、调试和文档生成正确。

为什么直接装饰函数会丢失 __name__ 和 __doc__?
装饰器本质是用新函数替换了原函数,而新函数的 __name__、__doc__、__module__ 等属性默认来自内部定义的函数(比如 wrapper),不是原始函数。不处理的话,help(my_func) 会显示装饰器内部函数的帮助,my_func.__name__ 会变成 'wrapper',调试和反射时容易误判。
functools.wraps 怎么用?必须加括号调用
functools.wraps 本身是个工厂函数,它接收被装饰函数作为参数,返回一个用于修饰 wrapper 的装饰器。漏掉括号(写成 @wraps)会导致 TypeError: wraps() missing 1 required positional argument: 'wrapped'。
正确写法是:
from functools import wraps
<p>def my_decorator(func):
@wraps(func) # ← 必须带 (func)
def wrapper(*args, *<em>kwargs):
print("before")
result = func(</em>args, **kwargs)
print("after")
return result
return wrapper</p>
这样 wrapper 就会自动复制 func 的 __name__、__doc__、__module__、__annotations__ 和 __dict__(部分)。
Python 3.14.2是Python编程语言在2025年12月5日发布的稳定版本,属于3.14系列的第二个维护更新。该版本包含了18项修复,重点解决了多进程、数据类及正则表达式等模块的回归问题,并修复了CVE-2025-12084等安全漏洞。此版本标志着自由线程模式(移除GIL)正式获得官方支持,是Python发展的重要里程碑。
哪些属性会被保留?哪些不会?
@wraps(func) 默认复制以下属性:__module__、__name__、__qualname__、__doc__、__annotations__。但以下情况仍需手动处理:
-
__defaults__和__kwdefaults__:Python 3.9+ 的wraps已支持,旧版本需手动赋值 - 自定义属性(如
func.version = "1.2"):不会自动复制,得在wrapper里显式设置 -
__code__:永远不会复制——这是函数逻辑本体,替换后必然不同 - 被装饰函数的
__dict__中非字符串键值对:部分版本可能跳过,建议只存字符串键
不用 wraps 的替代方案有哪些?
极少数场景下你可能不想用 wraps,比如想隐藏原函数名、或统一暴露某个接口名。此时可手动设置关键属性:
def my_decorator(func):
def wrapper(*args, **kwargs):
...
wrapper.__name__ = func.__name__
wrapper.__doc__ = func.__doc__
wrapper.__module__ = func.__module__
return wrapper
但这种方式容易遗漏(比如忘了 __annotations__),且不随 Python 版本演进自动适配,维护成本高。除非有明确理由,否则别绕开 wraps。
真正容易被忽略的是:如果装饰器本身带参数(即三层嵌套),@wraps 必须放在最内层的 wrapper 上,而不是中间的 decorator 函数上。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










