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

执行流程

  1. @repeat(n=3) 先调用 repeat(3),返回 decorator 函数。
  2. decorator 接收 greet 函数作为参数,返回 wrapper 函数。
  3. 调用 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
  • 执行时先运行最外层的装饰器逻辑(decorator1wrapper),再依次向内。

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)。
Python中的装饰器参数传递与多层装饰器 描述 装饰器是Python中用于修改或增强函数行为的工具。当装饰器本身需要参数(如 @decorator(arg) )或需要多层嵌套时,参数传递机制会变得复杂。本题将深入讲解装饰器的参数传递流程、多层装饰器的执行顺序,以及如何设计可接受参数的装饰器。 1. 简单装饰器回顾 首先,回顾无参数的装饰器基本结构: 关键点 : @my_decorator 等价于 say_hello = my_decorator(say_hello) 。 装饰器接收一个函数( func )作为参数,并返回一个新函数( wrapper )。 2. 带参数的装饰器 若需要让装饰器接受自定义参数(如 @repeat(n=3) ),需再嵌套一层函数: 执行流程 : @repeat(n=3) 先调用 repeat(3) ,返回 decorator 函数。 decorator 接收 greet 函数作为参数,返回 wrapper 函数。 调用 greet("Alice") 实际执行 wrapper("Alice") 。 3. 多层装饰器的执行顺序 当多个装饰器堆叠时,执行顺序由下往上(或由内向外): 等价代码 : my_func = decorator1(decorator2(my_func)) 先应用 decorator2 ,再应用 decorator1 。 执行时先运行最外层的装饰器逻辑( decorator1 的 wrapper ),再依次向内。 4. 保留原函数的元信息 装饰器会覆盖原函数的名称、文档等元信息,需使用 functools.wraps 修复: 5. 综合示例:带参数的多层装饰器 结合参数传递与多层装饰器,实现一个记录日志且可重复执行的函数: 总结 装饰器参数传递 :通过三层嵌套函数实现,外层接收参数,中层接收函数,内层实现逻辑。 多层装饰器顺序 :从下往上应用,从上往下执行。 元信息保留 :使用 functools.wraps 避免被装饰函数身份丢失。 设计原则 :确保装饰器返回的函数签名与原函数一致(使用 *args, **kwargs )。