Python 向装饰器添加参数

  • Post category:Python

在Python中,装饰器是一种可以动态修改函数或类行为的函数。但有时我们需要为装饰器添加参数,以便在不同场合下对函数或类采取不同的处理方式。下面我们将详细讲解Python如何向装饰器添加参数以及使用方法,同时提供两个示例说明。

添加参数的装饰器

在Python中,向装饰器添加参数的方式比较简单,只需要在原有装饰器函数外层再定义一个带参数的函数,将原有装饰器函数作为内部函数,并返回内部函数,即可实现向装饰器添加参数。

以下是一个添加参数的装饰器模板:

def decorator_with_args(arg1, arg2, ...):
    def decorator(func):
        def wrapper(*args, **kwargs):
            # 添加装饰器代码
            return func(*args, **kwargs)
        return wrapper
    return decorator

其中,decorator_with_args是带参数的函数,decorator是装饰器函数,wrapper是具体行为实现函数,func则是被装饰的函数。

示例一:带参数的装饰器实现函数缓存

以下示例演示如何使用带参数的装饰器实现函数缓存:

import functools

def cache(maxsize=None):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            key = str(args) + str(kwargs)
            if key in wrapper.cache:
                return wrapper.cache[key]
            result = func(*args, **kwargs)
            if maxsize is not None and len(wrapper.cache) >= maxsize:
                wrapper.cache.popitem(last=False)
            wrapper.cache[key] = result
            return result
        wrapper.cache = {}
        return wrapper
    return decorator

在这个例子中,我们定义了一个带参数的装饰器cache,该装饰器可以接受一个整数类型的参数maxsize,表示缓存最大值。装饰器函数实现了一个缓存机制,使用字典来存储已经执行过的函数结果。在执行每个被装饰的函数时,我们先判断函数参数和关键字参数是否已经在缓存中,如果已经缓存,直接返回缓存的结果即可,否则执行函数并将结果加入到缓存中。当缓存大小超过最大值时,删除最早缓存的函数结果。

示例使用如下:

@cache(maxsize=10)
def fib(n):
    if n < 2:
        return n
    return fib(n-1) + fib(n-2)

print([fib(i) for i in range(20)])

以上代码会输出斐波那契数列的前20项,按顺序依次计算,但输出的结果中包含了缓存的项。

示例二:带参数的装饰器实现函数日志记录

以下示例演示如何使用带参数的装饰器实现函数执行日志记录:

def log(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print(f"call function {func.__name__}({args}, {kwargs})")
        return func(*args, **kwargs)
    return wrapper

def debug_log(level):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            print(f"[DEBUG-{level}] call function {func.__name__}({args}, {kwargs})")
            return func(*args, **kwargs)
        return wrapper
    return decorator

在这个例子中,我们定义了一个不带参数的装饰器log,该装饰器每次记录函数的调用情况。同时,我们定义了一个带参数的装饰器debug_log,该装饰器可以接受一个整数类型的参数level,表示调试日志级别。装饰器函数实现了一个带级别的调试日志记录功能,与log相似,但是在输出日志信息前增加了调试级别前缀。

示例使用如下:

@log
@debug_log(level=1)
def func(x, y):
    return x + y

func(1, 2)

以上代码执行后会输出以下信息:

[DEBUG-1] call function func((1, 2), {})
call function wrapper((1, 2), {})

可以看到,debug_log装饰器输出了带有调试级别前缀的函数调用信息,log装饰器则输出了函数名称和参数信息。