装饰器详解
装饰器详解
装饰器是Python中最强大的语法特性之一,它允许你在不修改原函数代码的情况下,为函数添加额外的功能。装饰器本质上是一个高阶函数,接受一个函数作为参数,返回一个新函数。
基本装饰器
装饰器使用 @ 语法糖,将一个函数应用到另一个函数上:
import functools
def timer(func):
"""计时装饰器"""
@functools.wraps(func)
def wrapper(*args, **kwargs):
import time
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"{func.__name__} 执行耗时: {end - start:.4f}秒")
return result
return wrapper
@timer
def slow_function():
import time
time.sleep(1)
return "完成"
slow_function()
# 输出: slow_function 执行耗时: 1.0012秒
带参数的装饰器
当装饰器需要接受参数时,需要再套一层函数:
import functools
def repeat(times):
"""重复执行装饰器"""
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
result = None
for _ in range(times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@repeat(times=3)
def greet(name):
print(f"你好, {name}!")
greet("Python")
# 输出3次: 你好, Python!
functools.wraps 的作用
使用装饰器时,原函数的元信息(如函数名、文档字符串)会被wrapper函数覆盖。functools.wraps 可以保留这些信息:
import functools
def my_decorator(func):
@functools.wraps(func) # 保留原函数信息
def wrapper(*args, **kwargs):
"""wrapper的文档"""
return func(*args, **kwargs)
return wrapper
@my_decorator
def example():
"""这是example的文档"""
pass
print(example.__name__) # example(而非wrapper)
print(example.__doc__) # 这是example的文档
类装饰器
除了函数,类也可以作为装饰器。类装饰器需要实现 __call__ 方法:
import functools
class CountCalls:
"""统计函数调用次数的类装饰器"""
def __init__(self, func):
functools.update_wrapper(self, func)
self.func = func
self.num_calls = 0
def __call__(self, *args, **kwargs):
self.num_calls += 1
print(f"调用 {self.func.__name__} 第 {self.num_calls} 次")
return self.func(*args, **kwargs)
def reset_count(self):
self.num_calls = 0
@CountCalls
def say_hello():
print("Hello!")
say_hello() # 调用 say_hello 第 1 次
say_hello() # 调用 say_hello 第 2 次
print(say_hello.num_calls) # 2
装饰器堆叠
多个装饰器可以堆叠使用,执行顺序从下到上:
import functools
def bold(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
return f"<b>{func(*args, **kwargs)}</b>"
return wrapper
def italic(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
return f"<i>{func(*args, **kwargs)}</i>"
return wrapper
@bold
@italic
def hello(name):
return f"Hello, {name}"
print(hello("World")) # <b><i>Hello, World</i></b>
实战:缓存装饰器
import functools
def memoize(func):
"""带缓存的装饰器"""
cache = {}
@functools.wraps(func)
def wrapper(*args):
if args not in cache:
cache[args] = func(*args)
return cache[args]
wrapper.cache = cache
return wrapper
@memoize
def fibonacci(n):
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
print(fibonacci(100)) # 秒出结果
常见使用场景
- 日志记录:自动记录函数调用和参数
- 性能计时:测量函数执行时间
- 权限验证:检查用户权限后再执行函数
- 缓存:缓存函数计算结果
- 重试机制:函数失败时自动重试
掌握装饰器是Python进阶的关键一步,它让你的代码更加优雅和模块化。