在 Python 中,装饰器(Decorator) 是一种特殊的函数,它允许你在不修改原有代码的情况下,扩展或修改其他函数的行为。装饰器本质上是一个高阶函数,它接受一个函数作为输入,并返回一个新的函数。
def logger(func):
def wrapper(*args, **kwargs):
print(f"[INFO] 调用函数: {func.__name__}")
result = func(*args, **kwargs) # 执行原函数
print(f"[INFO] 函数返回: {result}")
return result
return wrapper
@logger
def add(a, b):
return a + b
# 等价于 add = logger(add)
@logger
语法糖装饰 add
函数时,Python 会自动执行 add = logger(add)
。logger
函数返回 wrapper
函数,因此 add
现在指向 wrapper
。add(3, 5)
时,实际上调用的是 wrapper(3, 5)
,它会先打印日志,再执行原函数,最后打印返回结果。如果装饰器需要接受额外参数(如日志级别、重试次数),可以定义一个“装饰器工厂”函数。
def repeat(n):
def decorator(func):
def wrapper(*args, **kwargs):
result = None
for _ in range(n):
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@repeat(3) # 等价于 add = repeat(3)(add)
def greet(name):
print(f"Hello, {name}!")
多个装饰器可以叠加使用,执行顺序是从下到上(即靠近函数定义的装饰器先执行)。
def bold(func):
def wrapper():
return f"{func()}"
return wrapper
def italic(func):
def wrapper():
return f"{func()}"
return wrapper
@bold
@italic
def text():
return "Hello"
print(text()) # 输出: Hello
使用 functools.wraps
装饰器保留原函数的名称、文档字符串等元信息。
import functools
def logger(func):
@functools.wraps(func) # 保留原函数元信息
def wrapper(*args, **kwargs):
print(f"调用函数: {func.__name__}")
return func(*args, **kwargs)
return wrapper
@logger
def add(a, b):
"""计算两数之和"""
return a + b
print(add.__name__) # 输出: add(而不是 wrapper)
print(add.__doc__) # 输出: 计算两数之和
除了函数装饰器,还可以使用类来实现装饰器。类装饰器需要实现 __call__
方法。
class CountCalls:
def __init__(self, func):
self.func = func
self.count = 0 # 记录调用次数
def __call__(self, *args, **kwargs):
self.count += 1
print(f"第 {self.count} 次调用 {self.func.__name__}")
return self.func(*args, **kwargs)
@CountCalls
def say_hello():
print("Hello!")
say_hello() # 输出: 第 1 次调用 say_hello
say_hello() # 输出: 第 2 次调用 say_hello
使用 functools.lru_cache
缓存函数结果,避免重复计算。
import functools
@functools.lru_cache(maxsize=128)
def fib(n):
if n < 2:
return n
return fib(n-1) + fib(n-2)
测量函数执行时间。
import time
def timer(func):
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"{func.__name__} 执行时间: {end - start:.4f} 秒")
return result
return wrapper
@timer
def process_data():
time.sleep(1)
在执行函数前验证用户权限。
def requires_admin(func):
def wrapper(user, *args, **kwargs):
if user["role"] != "admin":
raise PermissionError("需要管理员权限")
return func(user, *args, **kwargs)
return wrapper
@requires_admin
def delete_user(user, username):
print(f"删除用户: {username}")
wrapper
函数需要接受 *args
和 **kwargs
,以处理原函数的任意参数。wrapper
函数必须返回原函数的结果(即调用 func(*args, **kwargs)
)。functools.wraps
,装饰后的函数元信息(如 __name__
、__doc__
)会被修改。