Python中的函数装饰器参数传递与多层装饰器执行顺序
字数 519 2025-11-24 11:49:07
Python中的函数装饰器参数传递与多层装饰器执行顺序
知识点描述
装饰器是Python中用于修改或增强函数行为的强大工具。当装饰器本身需要参数,或者多个装饰器堆叠使用时,参数传递和执行顺序就变得复杂。理解装饰器参数如何传递以及多层装饰器的执行顺序,对于编写和调试装饰器代码至关重要。
详细讲解
1. 基础装饰器回顾
首先回忆简单装饰器的结构:
def decorator(func):
def wrapper(*args, **kwargs):
# 增强功能
result = func(*args, **kwargs)
# 后续处理
return result
return wrapper
@decorator
def target_function():
pass
这里的@decorator是语法糖,等价于target_function = decorator(target_function)。
2. 带参数的装饰器
当装饰器本身需要接收参数时,需要三层嵌套函数:
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 greet(name):
print(f"Hello {name}")
# 执行过程分解:
# 1. repeat(3) 返回decorator函数
# 2. decorator(greet) 返回wrapper函数
# 3. 实际调用的是wrapper("Alice")
3. 多层装饰器的执行顺序
当多个装饰器堆叠时,执行顺序是从下往上装饰,从上往下执行:
def decorator1(func):
print("decorator1 applied")
def wrapper():
print("decorator1 before")
func()
print("decorator1 after")
return wrapper
def decorator2(func):
print("decorator2 applied")
def wrapper():
print("decorator2 before")
func()
print("decorator2 after")
return wrapper
@decorator1
@decorator2
def original():
print("original function")
# 装饰阶段(从下往上):
# 1. original = decorator2(original) → 打印"decorator2 applied"
# 2. original = decorator1(original) → 打印"decorator1 applied"
# 调用original()时的执行顺序(从上往下):
# decorator1 before
# decorator2 before
# original function
# decorator2 after
# decorator1 after
4. 复杂情况:带参数的多层装饰器
结合前两种情况,分析最复杂的场景:
def validate_input(validator):
def decorator(func):
def wrapper(*args, **kwargs):
if not validator(*args, **kwargs):
raise ValueError("Invalid input")
return func(*args, **kwargs)
return wrapper
return decorator
def log_call(level="INFO"):
def decorator(func):
def wrapper(*args, **kwargs):
print(f"[{level}] Calling {func.__name__}")
return func(*args, **kwargs)
return wrapper
return decorator
@validate_input(lambda x: x > 0) # 最外层装饰器
@log_call(level="DEBUG") # 中间层装饰器
def calculate_square(x):
return x * x
# 装饰过程分解:
# 1. log_call("DEBUG")返回decorator_l1
# 2. decorator_l1(calculate_square)返回wrapper_l1
# 3. validate_input(lambda x: x > 0)返回decorator_v1
# 4. decorator_v1(wrapper_l1)返回最终的wrapper_v1
# 调用calculate_square(2)时的执行流:
# 1. validate_input的wrapper检查参数
# 2. log_call的wrapper打印日志
# 3. 执行原始函数calculate_square
5. 使用functools.wraps保持元信息
为了避免装饰器掩盖原函数的元信息,应该使用functools.wraps:
from functools import wraps
def decorator(func):
@wraps(func) # 将原函数的元信息复制到wrapper
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
关键要点总结
- 装饰器参数传递需要三层嵌套函数结构
- 多层装饰器装饰时从下往上,执行时从上往下
- 使用
@wraps保持函数元信息 - 理解装饰器的实际等价转换有助于调试复杂情况