在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
装饰器则输出了函数名称和参数信息。