理解装饰器:未指定参数时返回类型是一个函数

我将单个装饰器用于两个独立的函数:一个具有装饰器参数的规范;另一个没有它.

当不传递可选参数时,返回类型是一个函数(特别是装饰器中的inner_function).但是,当传递可选参数时,它将按预期工作.

您能解释一下这里发生了什么,以及为什么在这些情况下行为有所不同吗?

def cache_disk(cache_folder="./cache"):
    def wrapper(f):
        def inner_function(*args, **kwargs):
            result = f(*args, **kwargs)
            return result
        return inner_function
    return wrapper

@cache_disk
def func1(data):
    return [d for d in data]

@cache_disk(cache_folder='./cache/')
def func2(data):
    return [d for d in data]


data = [1,2,3]
print(func1(data))
print(func2(data))

结果:

<function inner_function at 0x7f1f283d5c08>
[1, 2, 3]

解决方法:

注意:

@decorator  # no arguments
def func(...):
    ...

等效于:

def func(...):
    ...

func = decorator(func)  # one 'level' of calls

然后:

@decorator(...):  # arguments
def func(...):
    ...

等效于:

def func(...):
    ...

func = decorator(...)(func)  # two 'levels' of calls

在第一种情况下,装饰器只有一个参数,即函子本身.在第二种情况下,装饰器的参数是@行中的…,而装饰器返回的函数则以func作为参数来调用.

在您的示例中

@cache_disk
def func1(data):
    ...

装饰器cache_disk将获得一个可调用的单个参数(func,它将变为args [0])并返回包装器.然后,当您致电:

print(func1(data))

包装器获取单个参数(数据,该参数变为f)并返回inner_function.

因此,您有三个选择:

>用@cache_disk()装饰func1(注意括号),不将参数传递给cache_disk本身,而将func传递给包装器;
>改变cache_disk的行为,取决于是否传递了单个可调用参数或其他参数;要么
>如注释中指出的@o11c,请使用cache_disk.wrapper = cache_disk()为无参数版本提供方便的别名,然后使用@ cache_disk.wrapper装饰.

上一篇:我们可以使用装饰器设计任何函数吗?


下一篇:python-使用类作为方法装饰器