在 Python 编程中,装饰器是一种设计模式,它允许我们以声明的方式修改或增强一个函数或方法的行为,而无需永久性地修改其源代码。装饰器本质上是一个接受函数作为参数并返回一个新函数的高阶函数。它们广泛应用于日志记录、缓存、权限验证等多个领域,是提升代码可读性和复用性的重要工具。
一、装饰器的基本用法
最简单的装饰器形式是将一个函数作为参数传递给另一个函数,这被称为高阶函数。例如,我们有一个函数add
, 我们希望在其执行前后打印一些信息,就可以创建一个装饰器函数log_decorator
来实现这个功能。
def log_decorator(func):
def wrapper(*args, **kwargs):
print("Before calling function")
result = func(*args, **kwargs)
print("After calling function")
return result
return wrapper
@log_decorator
def add(a, b):
return a + b
# 输出:
# Before calling function
# After calling function
# 3
在上面的例子中,log_decorator
是一个装饰器,它接收一个函数 func
作为参数,并定义了一个内部函数 wrapper
,该函数在调用前后打印信息。使用 @log_decorator
语法糖来装饰 add
函数,当我们调用 add(1, 2)
时,实际上是调用了 wrapper(1, 2)
。
二、更复杂的应用场景
1. 带参数的装饰器
有时,我们可能需要给装饰器传递参数。可以通过嵌套函数的方式来实现这一点。
def repeat(n):
def actual_decorator(func):
def wrapper(*args, **kwargs):
for _ in range(n):
result = func(*args, **kwargs)
return result
return wrapper
return actual_decorator
@repeat(3)
def say_hello(name):
print(f"Hello, {name}!")
# 输出:
# Hello, Alice!
# Hello, Alice!
# Hello, Alice!
在这个例子中,我们定义了一个名为 repeat
的装饰器工厂,它接受一个参数 n
,并返回实际的装饰器 actual_decorator
。这样我们就可以根据需要重复执行被装饰的函数多次。
2. 类装饰器
除了函数装饰器外,Python还支持类装饰器。类装饰器可以更好地处理需要维护状态的情况。
class Repeat:
def __init__(self, n):
self.n = n
def __call__(self, func):
def wrapper(*args, **kwargs):
for _ in range(self.n):
result = func(*args, **kwargs)
return result
return wrapper
@Repeat(3)
def say_goodbye(name):
print(f"Goodbye, {name}!")
# 输出:
# Goodbye, Bob!
# Goodbye, Bob!
# Goodbye, Bob!
这里,Repeat
类定义了一个 __call__
方法,使得其实例可以像函数一样被调用。这样我们就可以像使用函数装饰器一样使用类装饰器。
三、结合实际问题的应用
假设我们正在开发一个 Web 应用,需要对某些视图函数进行权限验证。我们可以编写一个名为 require_authentication
的装饰器来实现这一功能。
def require_authentication(func):
@wraps(func)
def wrapper(*args, **kwargs):
if not current_user.is_authenticated():
raise PermissionDenied()
return func(*args, **kwargs)
return wrapper
@require_authentication
def edit_profile():
# Edit profile code here
pass
在这个例子中,require_authentication
装饰器用于确保用户已登录才允许访问 edit_profile
函数。如果当前用户未通过身份验证,则会引发 PermissionDenied
异常。
总之,Python 中的装饰器提供了一种灵活而强大的方式来扩展和重用心。无论是简单的日志记录还是复杂的权限验证逻辑,都可以借助装饰器来实现。通过合理利用装饰器,我们可以大大提高代码的可维护性和复用性。