Python 装饰器详解
装饰器(Decorator)是 Python 中一种非常强大的功能,允许我们在不修改函数或方法本体的情况下,增强其功能。它通常用于函数的包装,使得原本简单的函数能够变得更加灵活和功能强大。装饰器的本质是接受一个函数作为参数,并返回一个新的函数。它可以用来修改或扩展原函数的行为。
1. 装饰器的基本语法
装饰器通常有以下两种定义方式:
def decorator_function(func):
def wrapper():
# 可以在原函数调用前后增加功能
print("Before function call")
func() # 调用原函数
print("After function call")
return wrapper
然后,我们可以使用 @ 符号将装饰器应用到函数上:
@decorator_function
def say_hello():
print("Hello!")
这个 @decorator_function 是装饰器语法糖,实际上等价于:
say_hello = decorator_function(say_hello)
2. 装饰器工作原理
- 原函数:
say_hello函数定义了它的行为。 - 装饰器:
decorator_function接受原函数say_hello作为参数。 - 包装函数:
wrapper是装饰器中的内嵌函数,它在原函数执行前后可以加入额外的逻辑。
示例 1:最基本的装饰器
def decorator_function(func):
def wrapper():
print("Before function call")
func() # 调用原函数
print("After function call")
return wrapper
@decorator_function
def say_hello():
print("Hello!")
# 调用装饰后的函数
say_hello()
# 输出:
# Before function call
# Hello!
# After function call
3. 带参数的装饰器
如果原函数带有参数,装饰器中的 wrapper 也需要接受这些参数并将其传递给原函数。
示例 2:带参数的装饰器
def decorator_function(func):
def wrapper(*args, **kwargs): # 接受任意数量的参数
print("Before function call")
result = func(*args, **kwargs) # 将参数传递给原函数
print("After function call")
return result
return wrapper
@decorator_function
def greet(name):
print(f"Hello, {name}!")
greet("Alice")
# 输出:
# Before function call
# Hello, Alice!
# After function call
在上面的示例中,*args 和 **kwargs 允许装饰器函数处理任意类型的参数。
4. 带返回值的装饰器
装饰器可以在原函数执行前、执行后或替代原函数返回结果。
示例 3:返回值的装饰器
def decorator_function(func):
def wrapper(*args, **kwargs):
print("Before function call")
result = func(*args, **kwargs) # 获取原函数的返回值
print("After function call")
return result # 返回原函数的结果
return wrapper
@decorator_function
def add(a, b):
return a + b
result = add(5, 7)
print(f"Result: {result}")
# 输出:
# Before function call
# After function call
# Result: 12
5. 带参数和返回值的装饰器
装饰器不仅可以修改函数的行为,还可以增强函数的功能,比如日志记录、权限校验等。
示例 4:带参数和返回值的装饰器
def decorator_function(func):
def wrapper(*args, **kwargs):
print(f"Arguments were: {args}, {kwargs}")
result = func(*args, **kwargs)
print(f"Returned: {result}")
return result
return wrapper
@decorator_function
def multiply(x, y):
return x * y
multiply(3, 4)
# 输出:
# Arguments were: (3, 4), {}
# Returned: 12
6. 装饰器的应用
装饰器广泛应用于各种场景,如:
- 日志记录:记录函数的调用、参数和返回值。
- 权限校验:确保用户拥有访问某个资源的权限。
- 性能监测:测量函数执行时间。
- 缓存:存储和复用函数结果,避免重复计算。
7. 装饰器链
多个装饰器可以叠加在同一个函数上,装饰器会按照从内到外的顺序执行。
示例 5:装饰器链
def decorator1(func):
def wrapper():
print("Decorator 1")
return func()
return wrapper
def decorator2(func):
def wrapper():
print("Decorator 2")
return func()
return wrapper
@decorator1
@decorator2
def say_hello():
print("Hello!")
say_hello()
# 输出:
# Decorator 1
# Decorator 2
# Hello!
8. functools.wraps:保持函数元数据
当使用装饰器时,原函数的元数据(如函数名、文档字符串等)会被 wrapper 函数覆盖。为了保留原函数的元数据,可以使用 functools.wraps。
示例 6:使用 wraps
from functools import wraps
def decorator_function(func):
@wraps(func) # 保留原函数的元数据
def wrapper(*args, **kwargs):
print("Before function call")
return func(*args, **kwargs)
return wrapper
@decorator_function
def say_hello():
"""A simple greeting function"""
print("Hello!")
print(say_hello.__name__) # 输出 say_hello
print(say_hello.__doc__) # 输出 A simple greeting function
9. 总结
- 装饰器 是一种设计模式,可以修改函数或方法的行为而不直接修改它们的源代码。
- 它们广泛应用于函数增强、日志记录、权限验证、缓存、性能监控等场景。
- 装饰器使用
@语法应用,可以带有参数、返回值,并且支持链式使用。 - 使用
functools.wraps可以保留原函数的元数据。
更多详细内容请关注其他相关!