今日学习目标
- 了解装饰器的基本概念和作用
- 学习如何定义和使用装饰器
- 掌握带参数的装饰器
- 理解保留原函数元数据的方式
- 学习类装饰器的用法
- 了解装饰器的实际应用场景
1. 基本装饰器
定义和使用
装饰器是一个函数,它接受另一个函数作为参数,并返回一个新的函数。装饰器常用于在函数调用前后添加额外的行为,而无需修改函数本身。
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(func)
:定义了一个装饰器函数,它接受一个函数func
作为参数。wrapper
:在装饰器内部定义了一个新函数wrapper
,它包装了func
,在func
调用前后添加了额外的打印语句。@my_decorator
:装饰器语法,等效于say_hello = my_decorator(say_hello)
。
2. 带参数的装饰器
使用 *args
和 **kwargs
为了使装饰器能够处理带参数的函数,我们可以使用 *args
和 **kwargs
。
def my_decorator(func):
def wrapper(*args, **kwargs):
print("Something is happening before the function is called.")
result = func(*args, **kwargs)
print("Something is happening after the function is called.")
return result
return wrapper
@my_decorator
def say_hello(name):
print(f"Hello, {name}!")
say_hello("Alice")
输出
Something is happening before the function is called.
Hello, Alice!
Something is happening after the function is called.
3. 返回值的处理
确保返回原函数的结果
装饰器通常会返回被装饰函数的结果,因此需要在 wrapper
函数中添加返回语句。
def my_decorator(func):
def wrapper(*args, **kwargs):
print("Before function call")
result = func(*args, **kwargs)
print("After function call")
return result
return wrapper
@my_decorator
def add(a, b):
return a + b
result = add(3, 5)
print(result)
输出
Before function call
After function call
8
4. 带参数的装饰器工厂
定义装饰器工厂
有时候我们需要创建带参数的装饰器。为此,我们需要使用多层嵌套函数。
def repeat(num_times):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(num_times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@repeat(num_times=3)
def say_hello(name):
print(f"Hello, {name}!")
say_hello("Alice")
输出
Hello, Alice!
Hello, Alice!
Hello, Alice!
5. 类装饰器
使用类实现装饰器
装饰器也可以通过类来实现。类装饰器需要实现 __call__
方法,使其实例能够像函数一样被调用。
class MyDecorator:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print("Before function call")
result = self.func(*args, **kwargs)
print("After function call")
return result
@MyDecorator
def say_hello(name):
print(f"Hello, {name}!")
say_hello("Alice")
输出
Before function call
Hello, Alice!
After function call
6. 保留原函数元数据
使用 functools.wraps
保留元数据
使用装饰器时,被装饰函数的元数据(如名称和文档字符串)可能会丢失。为了解决这个问题,可以使用 functools
模块中的 wraps
装饰器。
from functools import wraps
def my_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
print("Before function call")
result = func(*args, **kwargs)
print("After function call")
return result
return wrapper
@my_decorator
def say_hello(name):
"""This is the say_hello function"""
print(f"Hello, {name}!")
print(say_hello.__name__)
print(say_hello.__doc__)
输出
say_hello
This is the say_hello function
7. 实际应用场景
示例:日志记录装饰器
def log_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
print(f"Calling function {func.__name__} with arguments {args} and {kwargs}")
result = func(*args, **kwargs)
print(f"Function {func.__name__} returned {result}")
return result
return wrapper
@log_decorator
def add(a, b):
return a + b
add(3, 5)
输出
Calling function add with arguments (3, 5) and {}
Function add returned 8
总结
- 基本装饰器:装饰器函数接受一个函数作为参数,返回一个新的包装函数。
- 带参数的装饰器:使用
*args
和**kwargs
处理带参数的函数。 - 返回值的处理:确保装饰器返回原函数的结果。
- 带参数的装饰器工厂:使用嵌套函数创建带参数的装饰器。
- 类装饰器:通过实现
__call__
方法使类装饰器像函数一样被调用。 - 保留原函数元数据:使用
functools.wraps
保留原函数的元数据。 - 实际应用场景:装饰器广泛应用于日志记录、性能计数、访问控制、缓存和事务管理等场景。
通过理解装饰器的工作原理和各种用法,你可以在不修改原函数代码的情况下,灵活地为函数添加额外的功能。