上一篇
Python wraps函数使用教程 - 保留装饰器函数元信息
- Python
- 2025-07-18
- 696
Python中wraps函数使用教程
在Python中,装饰器是一个强大的功能,但在使用过程中可能会覆盖被装饰函数的元信息(如函数名、文档字符串等)。functools.wraps
函数就是用来解决这个问题的实用工具。
为什么需要wraps函数?
当我们使用装饰器时,实际上是用一个新的函数替换了原始函数。这会导致原始函数的一些元信息丢失:
- 函数名称(
__name__
)会变成装饰器内部函数的名称 - 文档字符串(
__doc__
)会被覆盖 - 函数的参数签名信息会丢失
- 调试信息可能变得不准确
wraps函数的基本用法
functools.wraps
是一个装饰器工厂函数,用于更新包装函数的元信息,使其看起来更像原始函数。
基本语法:
from functools import wraps
def decorator(func):
@wraps(func) # 使用wraps保留func的元信息
def wrapper(*args, **kwargs):
# 装饰器逻辑
return func(*args, **kwargs)
return wrapper
使用wraps与不使用wraps的对比
不使用wraps的装饰器
def simple_decorator(func):
def wrapper(*args, **kwargs):
"""装饰器的文档字符串"""
print(f"调用函数: {func.__name__}")
return func(*args, **kwargs)
return wrapper
@simple_decorator
def greet(name):
"""问候函数"""
return f"你好, {name}!"
# 测试元信息
print(greet.__name__) # 输出: wrapper
print(greet.__doc__) # 输出: 装饰器的文档字符串
使用wraps的装饰器
from functools import wraps
def better_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
"""装饰器的文档字符串"""
print(f"调用函数: {func.__name__}")
return func(*args, **kwargs)
return wrapper
@better_decorator
def greet(name):
"""问候函数"""
return f"你好, {name}!"
# 测试元信息
print(greet.__name__) # 输出: greet
print(greet.__doc__) # 输出: 问候函数
实际应用场景
1. 计时装饰器
import time
from functools import wraps
def timing_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"{func.__name__} 执行耗时: {end_time - start_time:.4f}秒")
return result
return wrapper
@timing_decorator
def calculate_sum(n):
"""计算从1到n的总和"""
return sum(range(1, n+1))
print(calculate_sum(1000000))
print(calculate_sum.__name__) # 输出: calculate_sum
print(calculate_sum.__doc__) # 输出: 计算从1到n的总和
2. 权限验证装饰器
from functools import wraps
def requires_admin(func):
@wraps(func)
def wrapper(user, *args, **kwargs):
if not user.get('is_admin', False):
raise PermissionError("需要管理员权限")
return func(user, *args, **kwargs)
return wrapper
@requires_admin
def delete_user(user, username):
"""删除指定用户"""
print(f"正在删除用户: {username}")
return True
# 测试
admin_user = {'name': 'admin', 'is_admin': True}
regular_user = {'name': 'user', 'is_admin': False}
print(delete_user(admin_user, "test_user")) # 成功执行
try:
delete_user(regular_user, "test_user") # 抛出异常
except PermissionError as e:
print(f"错误: {e}")
print(delete_user.__name__) # 输出: delete_user
wraps的高级用法
wraps
函数可以接受一些可选参数来进一步自定义行为:
def custom_decorator(func):
@wraps(
func,
assigned=('__module__', '__name__', '__qualname__', '__doc__', '__annotations__'),
updated=('__dict__',)
)
def wrapper(*args, **kwargs):
# 装饰器逻辑
return func(*args, **kwargs)
return wrapper
- assigned: 指定要更新的属性(默认为WRAPPER_ASSIGNMENTS)
- updated: 指定要合并的属性(默认为WRAPPER_UPDATES)
总结
functools.wraps
是创建装饰器时的最佳实践- 使用wraps可以保留原始函数的元信息(名称、文档字符串等)
- 使用wraps后,调试和文档生成工具能够正常工作
- 在定义任何装饰器时,都应该使用
@wraps(func)
- wraps也适用于类装饰器
通过本文,您应该已经掌握了Python中functools.wraps
函数的使用方法和重要性。在实际开发中,使用wraps可以避免许多元信息相关的问题,提高代码的可维护性和可读性。
本文由MouMing于2025-07-18发表在吾爱品聚,如有疑问,请联系我们。
本文链接:https://521pj.cn/20255898.html
发表评论