python中wraps的用法笔记

本文通过代码示例详细介绍了Python装饰器中的wraps用法,解释了不使用wraps时,被装饰函数的name和doc属性会改变,以及如何通过functools.wraps保持原函数属性不变,确保正确获取函数名和文档说明。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

学习就是投资自己!

一、没有wraps的代码执行

模板:
在这里插入图片描述
首先来说两个方法:
1,name:获取函数名称并显示
2,doc:获取文档说明并显示

代码示例1:
1,def m():
2, “”“这里是文档说明部分:《静夜思》”“”
3, print(‘第一句’,‘窗前明月光’)
4,if name==“main”:
5, print(“这里获取函数名:”,m.name)
6, print(“这里获取文档说明:”,m.doc)
在这里插入图片描述

执行结果:
在这里插入图片描述

代码示例2:
添加装饰器,但是不添加wraps
1,def wrapps(func):
2, def mama(*args,**kwargs):
3, print(“第二句”,‘疑似地上霜’)
4, return mama

5,@wrapps #添加装饰器
6,def m():
7, “”“这里是文档说明部分:《静夜思》”“”
8, print(‘第一句’,‘窗前明月光’)

9,if name==“main”:
10,print(“这里获取函数名:”,m.name)
11,print(“这里获取文档说明:”,m.doc)
在这里插入图片描述
Python 装饰器(decorator)在实现的时候,被装饰后的函数其实已经是另外一个函数了(函数名等函数属性会发生改变)
@ 符号是装饰器的语法糖。它放在一个函数开始定义的地方(头顶),和这个函数绑定在一起。
当我们调用这个函数的时候,会先将这个函数做为参数传入它头顶,即装饰器里。
第1行定义了一个函数wrapps(),第7行定义了一个函数m(),第六行添加了一个装饰器@wrapps,即给函数m()与wrapps()绑定在一起。第11,12行调用m.__name__和m.__doc__时,实际上是将m()函数作为参数传给了函数wrapps(),这是m.__name__返回的就是mama,而m.__doc__返回的时None。为什么m.__doc__返回的是None呢,是因为__doc__返回的内容是文档说明,即三组双引号"““说明””"的内容,而mama中没有文档说明,所以返回的时None。

那怎样才能是m.__name__和m.__doc__返回的是函数m()对应的函数名和文档说明呢。接下来我们对代码示例2使用装饰器。

代码示例3:
1,from functools import wraps
2,def wrapps(func):
3,@wraps(func)
4,def mama(*args,**kwargs):
5,print(“第二句”,‘疑似地上霜’)
6, func()
7, return mama
8,@wrapps
9,def m():
10, “”“这里是文档说明部分:《静夜思》”“”
11, print(‘第一句’,‘窗前明月光’)
12,if name==“main”:
13, print(“这里获取函数名:”,m.name)
14, print(“这里获取文档说明:”,m.doc)
在这里插入图片描述
执行结果:
在这里插入图片描述
当添加上装饰器@warps后,m.__name__返回的时m()的函数名称,而不是装饰器warpps的函数名称。

总结

加油!加油!加油!

<think>好的,我现在需要帮助用户理解Python中的@wraps装饰器的作用。首先,我应该回顾一下装饰器的基本概念,因为@wraps和装饰器密切相关。装饰器允许我们扩展函数的功能,但可能会覆盖原函数的元数据,比如__name__和__doc__。这时候@wraps的作用就体现出来了,它能够保留这些元数据。 接下来,我要确保自己正确理解@wraps的功能。根据提供的引用资料,特别是引用[1]到[4],@wraps来自functools模块,用于装饰器内部定义的包装函数。它的主要目的是将原函数的元数据复制到包装函数上,这样在查看函数名或文档字符串时,显示的是原函数的信息,而不是包装函数的。 用户的问题集中在@wraps的功能和作用上,所以需要明确回答这点。我需要分步骤解释,首先说明装饰器带来的元数据问题,然后引入@wraps如何解决这个问题。可能还需要通过示例代码对比使用和不使用@wraps的情况,让用户更直观地看到差异。 同时,用户提供的示例代码中,比如引用[3]中的例子,展示了使用@wraps后,函数a的__name__和__doc__仍然保持原样,而如果不使用的话,这些属性会指向包装函数b。这可以作为有力的例证来说明@wraps的重要性。 另外,需要指出@wraps的实际应用场景,比如在编写装饰器时,保持被装饰函数的元信息对于调试和文档生成非常重要。这能帮助用户理解为什么需要使用这个装饰器,而不仅仅是知道怎么用。 最后,生成相关问题时要考虑用户可能进一步想知道的内容,比如如何正确使用@wraps,或者在不同场景下的应用案例。这样可以帮助用户深入学习和解决可能遇到的问题。</think>### Python @wraps 装饰器的功能与作用 #### 1. 装饰器的元数据问题 当使用装饰器包装函数时,原始函数的元数据(如函数名 `__name__`、文档字符串 `__doc__`)会被包装函数的元数据覆盖。例如: ```python def decorator(func): def wrapper(): """包装函数文档""" return func() return wrapper @decorator def original(): """原始函数文档""" pass print(original.__name__) # 输出:wrapper print(original.__doc__) # 输出:包装函数文档 ``` 此时,被装饰的函数 `original` 的元信息丢失,影响调试和文档生成[^4]。 #### 2. @wraps 的核心作用 `@wraps` 装饰器通过**复制原函数的元数据到包装函数**,解决上述问题。使用方式如下: ```python from functools import wraps def decorator(func): @wraps(func) # 关键步骤:保留原函数元数据 def wrapper(): """包装函数文档""" return func() return wrapper @decorator def original(): """原始函数文档""" pass print(original.__name__) # 输出:original print(original.__doc__) # 输出:原始函数文档 ``` 此时,被装饰的函数仍保留原始元数据[^2][^3]。 #### 3. 技术实现原理 `@wraps(func)` 实际执行了以下操作: - 将 `func` 的 `__name__`、`__doc__`、`__module__` 等属性复制到包装函数 - 使 `help()` 和 IDE 提示显示原始函数信息 - 支持序列化(如 `pickle`)时识别原始函数[^1] #### 4. 典型应用场景 - 需要保留函数签名的装饰器(如日志记录、性能分析) - 生成API文档时保留函数说明 - 调试时准确定位原始函数位置 ```python from functools import wraps import time def timing_decorator(func): @wraps(func) def wrapper(*args, **kwargs): start = time.time() result = func(*args, **kwargs) end = time.time() print(f"{func.__name__} 耗时: {end-start:.2f}秒") return result return wrapper ``` #### 5. 注意事项 - 必须从 `functools` 导入 `wraps` - 应装饰在包装函数(如 `wrapper`)上,而非装饰器函数本身 - 对类方法装饰时同样有效
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值