Python装饰器是一种特殊的函数或类,它允许我们在不改变现有代码结构的情况下增加额外的功能。装饰器本质上是一个接受函数作为参数并返回一个新函数的高阶函数。
让我们从一个简单例子开始。假设我们有一个打印问候语的函数:
def greet():
print("Hello, world!")
我们希望每次调用这个函数时都能自动计算执行时间。这时可以定义一个装饰器来实现这个功能:
import time
def timer_decorator(func):
def wrapper():
start_time = time.time()
func()
end_time = time.time()
print("Execution time: {:.6f}s".format(end_time - start_time))
return wrapper
然后,我们可以在目标函数上应用这个装饰器:
greet = timer_decorator(greet)
greet() # 输出:"Hello, world!" 和执行时间
这里,timer_decorator
就是一个装饰器,它接收一个函数func
作为参数,并返回一个新的函数wrapper
。在wrapper
中,我们添加了计时的逻辑,并在调用原始函数前后分别获取时间来计算总执行时间。
现在,如果我们希望为多个函数添加相同的计时功能,可以使用@
语法糖简化代码:
@timer_decorator
def greet():
print("Hello, world!")
greet() # 输出:"Hello, world!" 和执行时间
@timer_decorator
就是将greet
函数作为参数传递给timer_decorator
,并将返回的新函数赋值给greet
。
进一步地,如果我们需要让装饰器接受参数,可以在外层再加一层函数。例如,我们可以定义一个通用的缓存装饰器:
def cache_decorator(cache_data):
def real_decorator(func):
cache = cache_data if isinstance(cache_data, dict) else {
}
def wrapper(*args):
if args in cache:
print("Cache hit!")
return cache[args]
else:
result = func(*args)
cache[args] = result
return result
return wrapper
return real_decorator
这个装饰器接受一个可选的缓存数据字典作为参数,用于存储之前计算过的结果。我们可以这样使用它:
@cache_decorator({
})
def add(a, b):
return a + b
add(1, 2) # 计算并缓存结果
add(1, 2) # 从缓存中获取结果
在这个例子中,第一次调用add(1, 2)
会计算结果并存入缓存,第二次调用则会直接从缓存中获取结果。
除了上述用法,装饰器还可以用来修改类的方法。例如,我们可以创建一个装饰器来验证类方法的访问权限:
def require_admin(func):
def wrapper(self, *args, **kwargs):
if not self.is_admin:
raise PermissionError("Admin privileges required")
return func(self, *args, **kwargs)
return wrapper
class User:
def __init__(self, is_admin=False):
self.is_admin = is_admin
@require_admin
def delete_user(self, user_id):
# 删除用户的实现
pass
在这个例子中,require_admin
装饰器确保只有管理员才能调用delete_user
方法。如果用户没有管理员权限,将抛出PermissionError
异常。
最后,值得注意的是,装饰器的堆叠顺序会影响最终的行为。当使用多个装饰器时,最接近目标函数的装饰器首先被应用,其次是外层的装饰器。这在设计复杂的装饰器链时非常重要。