文章目录深入理解 Python 的 __wrapped__ 属性一、什么是 __wrapped__二、为什么需要 __wrapped__三、functools.wraps 的作用四、__wrapped__ 的核心用途1. 访问原始函数2. 支持函数签名检查inspect3. 多层装饰器链4. 调试和工具支持五、实现原理简析六、最佳实践✅ 总是使用 functools.wraps❗ 不要手动忽略 __wrapped__七、总结深入理解 Python 的__wrapped__属性在 Python 的装饰器decorator体系中函数包装wrapping是一种非常常见的技术。然而函数一旦被装饰原始函数的元信息如名称、文档字符串、签名等往往会被覆盖。为了解决这个问题Python 引入了一个非常关键但容易被忽视的属性__wrapped__。本文将系统介绍__wrapped__的作用、原理以及实际应用场景。一、什么是__wrapped____wrapped__是一个函数属性用于指向被装饰前的原始函数。简单来说wrapped_function.__wrapped__original_function这个属性通常由标准库中的functools.wraps自动设置。二、为什么需要__wrapped__考虑一个最简单的装饰器defmy_decorator(func):defwrapper(*args,**kwargs):print(Before call)returnfunc(*args,**kwargs)returnwrapper使用它my_decoratordefadd(a,b):returnab此时print(add.__name__)# 输出: wrapper问题出现了原函数add的信息丢失了。三、functools.wraps的作用为了解决这个问题我们通常这样写fromfunctoolsimportwrapsdefmy_decorator(func):wraps(func)defwrapper(*args,**kwargs):print(Before call)returnfunc(*args,**kwargs)returnwrapperwraps(func)做了几件关键的事情复制元信息如__name__,__doc__设置__wrapped__属性等价于wrapper.__wrapped__func四、__wrapped__的核心用途1. 访问原始函数print(add.__wrapped__)# function add at ...甚至可以直接调用原始函数resultadd.__wrapped__(2,3)print(result)# 5跳过装饰器2. 支持函数签名检查inspectPython 的inspect模块会使用__wrapped__来获取真实函数签名importinspectprint(inspect.signature(add))如果没有__wrapped__签名会变成(*args, **kwargs)而不是(a, b)3. 多层装饰器链当有多个装饰器时decorator1decorator2deffunc():pass会形成链式结构func-wrapper1-wrapper2-original可以通过不断访问func.__wrapped__.__wrapped__逐层回溯到最初的函数。4. 调试和工具支持很多工具如调试器文档生成工具类型检查工具都会依赖__wrapped__来“还原”真实函数。五、实现原理简析functools.wraps本质上是一个装饰器工厂defwraps(wrapped):defdecorator(wrapper):wrapper.__wrapped__wrappedreturnwrapperreturndecorator实际实现中还会复制__module____name____qualname____doc____annotations__六、最佳实践✅ 总是使用functools.wrapsfromfunctoolsimportwraps这是推荐的标准写法否则调试困难introspection 失效工具链支持变差❗ 不要手动忽略__wrapped__如果你写自定义装饰器但不设置__wrapped__可能导致inspect失效FastAPI / Click 等框架行为异常七、总结__wrapped__虽然是一个小属性但在 Python 生态中扮演着关键角色保留函数原始引用支持 introspection自省让工具链正常工作提升调试体验一句话总结__wrapped__是装饰器世界中的“回溯指针”。
Python __wrapped__介绍(函数属性,用于指向被装饰前的原始函数)functools.wraps、函数签名检查inspect模块、多层装饰器链
文章目录深入理解 Python 的 __wrapped__ 属性一、什么是 __wrapped__二、为什么需要 __wrapped__三、functools.wraps 的作用四、__wrapped__ 的核心用途1. 访问原始函数2. 支持函数签名检查inspect3. 多层装饰器链4. 调试和工具支持五、实现原理简析六、最佳实践✅ 总是使用 functools.wraps❗ 不要手动忽略 __wrapped__七、总结深入理解 Python 的__wrapped__属性在 Python 的装饰器decorator体系中函数包装wrapping是一种非常常见的技术。然而函数一旦被装饰原始函数的元信息如名称、文档字符串、签名等往往会被覆盖。为了解决这个问题Python 引入了一个非常关键但容易被忽视的属性__wrapped__。本文将系统介绍__wrapped__的作用、原理以及实际应用场景。一、什么是__wrapped____wrapped__是一个函数属性用于指向被装饰前的原始函数。简单来说wrapped_function.__wrapped__original_function这个属性通常由标准库中的functools.wraps自动设置。二、为什么需要__wrapped__考虑一个最简单的装饰器defmy_decorator(func):defwrapper(*args,**kwargs):print(Before call)returnfunc(*args,**kwargs)returnwrapper使用它my_decoratordefadd(a,b):returnab此时print(add.__name__)# 输出: wrapper问题出现了原函数add的信息丢失了。三、functools.wraps的作用为了解决这个问题我们通常这样写fromfunctoolsimportwrapsdefmy_decorator(func):wraps(func)defwrapper(*args,**kwargs):print(Before call)returnfunc(*args,**kwargs)returnwrapperwraps(func)做了几件关键的事情复制元信息如__name__,__doc__设置__wrapped__属性等价于wrapper.__wrapped__func四、__wrapped__的核心用途1. 访问原始函数print(add.__wrapped__)# function add at ...甚至可以直接调用原始函数resultadd.__wrapped__(2,3)print(result)# 5跳过装饰器2. 支持函数签名检查inspectPython 的inspect模块会使用__wrapped__来获取真实函数签名importinspectprint(inspect.signature(add))如果没有__wrapped__签名会变成(*args, **kwargs)而不是(a, b)3. 多层装饰器链当有多个装饰器时decorator1decorator2deffunc():pass会形成链式结构func-wrapper1-wrapper2-original可以通过不断访问func.__wrapped__.__wrapped__逐层回溯到最初的函数。4. 调试和工具支持很多工具如调试器文档生成工具类型检查工具都会依赖__wrapped__来“还原”真实函数。五、实现原理简析functools.wraps本质上是一个装饰器工厂defwraps(wrapped):defdecorator(wrapper):wrapper.__wrapped__wrappedreturnwrapperreturndecorator实际实现中还会复制__module____name____qualname____doc____annotations__六、最佳实践✅ 总是使用functools.wrapsfromfunctoolsimportwraps这是推荐的标准写法否则调试困难introspection 失效工具链支持变差❗ 不要手动忽略__wrapped__如果你写自定义装饰器但不设置__wrapped__可能导致inspect失效FastAPI / Click 等框架行为异常七、总结__wrapped__虽然是一个小属性但在 Python 生态中扮演着关键角色保留函数原始引用支持 introspection自省让工具链正常工作提升调试体验一句话总结__wrapped__是装饰器世界中的“回溯指针”。