装饰器(decorators)是 Python 中的一种高级特性,它允许开发者修改函数或方法的行为,而不改变其定义。装饰器通常用于日志记录、权限检查、性能测量等场景。装饰器是通过在函数定义的前一行加上 @decorator_name
来使用的。
基本用法
装饰器本质上是一个函数,它接受一个函数作为参数,并返回一个新的函数。以下是一个简单的装饰器示例:
def my_decorator(func):
def wrapper():
print("Something is happening before the function is called.")
func()
print("Something is happening after the function is called.")
return wrapper
@my_decorator
def say_hello():
print("Hello!")
say_hello()
输出:
Something is happening before the function is called.
Hello!
Something is happening after the function is called.
在这个例子中:
my_decorator
是装饰器函数。say_hello
是被装饰的函数。@my_decorator
语法相当于say_hello = my_decorator(say_hello)
。
带参数的装饰器
如果需要在装饰器中传递参数,可以使用多层嵌套函数来实现:
def repeat(num_times):
def decorator_repeat(func):
def wrapper(*args, **kwargs):
for _ in range(num_times):
func(*args, **kwargs)
return wrapper
return decorator_repeat
@repeat(num_times=3)
def greet(name):
print(f"Hello {name}")
greet("World")
输出:
Hello World
Hello World
Hello World
在这个例子中:
repeat
是一个带参数的装饰器工厂,它返回一个装饰器。decorator_repeat
是实际的装饰器。wrapper
是包装函数,负责多次调用被装饰的函数func
。
类装饰器
装饰器也可以用于类。类装饰器是通过定义一个实现 __call__
方法的类来实现的:
class MyDecorator:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print("Class-based decorator before function call.")
result = self.func(*args, **kwargs)
print("Class-based decorator after function call.")
return result
@MyDecorator
def say_goodbye():
print("Goodbye!")
say_goodbye()
输出:
Class-based decorator before function call.
Goodbye!
Class-based decorator after function call.
在这个例子中:
MyDecorator
类实现了__call__
方法,使其实例可以像函数一样被调用。say_goodbye
函数被MyDecorator
实例装饰。
装饰器的实际应用
装饰器在实际开发中非常有用,以下是一些常见的应用场景:
- 日志记录:在函数执行前后记录日志。
- 权限检查:在执行函数前检查用户是否有权限。
- 性能测量:计算函数执行时间。
- 缓存:缓存函数的返回值,以提高性能。
- 输入校验:在函数执行前校验输入参数。
示例:日志记录装饰器
import functools
def log_decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__} with {args} and {kwargs}")
result = func(*args, **kwargs)
print(f"{func.__name__} returned {result}")
return result
return wrapper
@log_decorator
def add(a, b):
return a + b
add(2, 3)
输出:
Calling add with (2, 3) and {}
add returned 5
在这个例子中:
@functools.wraps(func)
保留了被装饰函数的元数据(如文档字符串和函数名)。log_decorator
在函数执行前后打印日志信息。
装饰器是一个强大而灵活的工具,能够极大地增强代码的可复用性和可读性。通过合理使用装饰器,可以使代码更加简洁、优雅。