Python中functools中wraps_Python装饰器中functools.wraps的作用

15次阅读

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

Python中functools中wraps_Python装饰器中functools.wraps的作用

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 functools 

def 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

立即学习Python免费学习笔记(深入)”;

容易忽略的一点:如果装饰器中修改了 __annotations__ 或动态加了 __dict__ 属性,wraps 不会同步这些改动——它只复制默认的可读元信息。需要额外处理时得手动赋值。

text=ZqhQzanResources