Python中的装饰器参数传递与多层装饰器
字数 923 2025-11-16 05:22:58
Python中的装饰器参数传递与多层装饰器
描述
装饰器是Python中用于修改或增强函数行为的工具。当装饰器本身需要参数(如@decorator(arg))或需要多层嵌套时,参数传递机制会变得复杂。本题将深入讲解装饰器的参数传递流程、多层装饰器的执行顺序,以及如何设计可接受参数的装饰器。
1. 简单装饰器回顾
首先,回顾无参数的装饰器基本结构:
def my_decorator(func):
def wrapper():
print("函数执行前")
func()
print("函数执行后")
return wrapper
@my_decorator
def say_hello():
print("Hello!")
say_hello()
# 输出:
# 函数执行前
# Hello!
# 函数执行后
关键点:
@my_decorator等价于say_hello = my_decorator(say_hello)。- 装饰器接收一个函数(
func)作为参数,并返回一个新函数(wrapper)。
2. 带参数的装饰器
若需要让装饰器接受自定义参数(如@repeat(n=3)),需再嵌套一层函数:
def repeat(n):
# 外层接收装饰器参数
def decorator(func):
# 中层接收被装饰的函数
def wrapper(*args, **kwargs):
# 内层实现装饰逻辑
for _ in range(n):
func(*args, **kwargs)
return wrapper
return decorator
@repeat(n=3)
def greet(name):
print(f"Hello {name}")
greet("Alice")
# 输出:
# Hello Alice
# Hello Alice
# Hello Alice
执行流程:
@repeat(n=3)先调用repeat(3),返回decorator函数。decorator接收greet函数作为参数,返回wrapper函数。- 调用
greet("Alice")实际执行wrapper("Alice")。
3. 多层装饰器的执行顺序
当多个装饰器堆叠时,执行顺序由下往上(或由内向外):
def decorator1(func):
def wrapper():
print("Decorator 1")
func()
return wrapper
def decorator2(func):
def wrapper():
print("Decorator 2")
func()
return wrapper
@decorator1
@decorator2
def my_func():
print("Original function")
my_func()
# 输出:
# Decorator 1
# Decorator 2
# Original function
等价代码:
my_func = decorator1(decorator2(my_func))
- 先应用
decorator2,再应用decorator1。 - 执行时先运行最外层的装饰器逻辑(
decorator1的wrapper),再依次向内。
4. 保留原函数的元信息
装饰器会覆盖原函数的名称、文档等元信息,需使用 functools.wraps 修复:
from functools import wraps
def logged(func):
@wraps(func)
def wrapper(*args, **kwargs):
print(f"调用函数: {func.__name__}")
return func(*args, **kwargs)
return wrapper
@logged
def add(a, b):
"""返回两数之和"""
return a + b
print(add.__name__) # 输出 "add"(而非 "wrapper")
print(add.__doc__) # 输出 "返回两数之和"
5. 综合示例:带参数的多层装饰器
结合参数传递与多层装饰器,实现一个记录日志且可重复执行的函数:
from functools import wraps
def repeat(n):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
for i in range(n):
print(f"第 {i+1} 次执行")
result = func(*args, **kwargs)
return result
return wrapper
return decorator
def logged(func):
@wraps(func)
def wrapper(*args, **kwargs):
print(f"参数: {args}, {kwargs}")
return func(*args, **kwargs)
return wrapper
@repeat(2)
@logged
def multiply(a, b):
return a * b
print(multiply(3, 4))
# 输出:
# 第 1 次执行
# 参数: (3, 4), {}
# 第 2 次执行
# 参数: (3, 4), {}
# 12
总结
- 装饰器参数传递:通过三层嵌套函数实现,外层接收参数,中层接收函数,内层实现逻辑。
- 多层装饰器顺序:从下往上应用,从上往下执行。
- 元信息保留:使用
functools.wraps避免被装饰函数身份丢失。 - 设计原则:确保装饰器返回的函数签名与原函数一致(使用
*args, **kwargs)。