【问题标题】:Understanding decorators: return type is a function when argument not specified了解装饰器:未指定参数时返回类型是函数
【发布时间】:2015-08-31 13:23:01
【问题描述】:

我将一个装饰器用于两个独立的功能:一个带有装饰器参数的规范;另一个没有它。

不传递可选参数时,返回类型为函数(具体为装饰器中的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]

【问题讨论】:

    标签: python decorator python-decorators


    【解决方案1】:

    注意:

    @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 本身。在第二种情况下,装饰器的参数是来自@ 行的...,它是装饰器返回的函数,它以func 作为参数调用。 p>


    在你的例子中,

    @cache_disk
    def func1(data):
        ...
    

    装饰器cache_disk 得到一个可调用的参数(func,它变成args[0])并返回wrapper。然后当你打电话时:

    print(func1(data))
    

    wrapper 获取单个参数(data,变为f)并返回inner_function

    因此,您有三个选择:

    1. @cache_disk()(注意括号)装饰func1,不向cache_disk本身和func传递参数给wrapper
    2. 改变cache_disk 的行为取决于它是否传递了单个可调用参数或其他东西;或
    3. 正如@o11c 在 cmets 中指出的那样,使用例如cache_disk.wrapper = cache_disk() 为无参数版本提供一个方便的别名,然后用@cache_disk.wrapper 装饰。

    【讨论】:

    • 值得注意的是,一些装饰器库使用@x vs @x.y 来区分大小写。
    • @o11c 在这种情况下会像允许@cache_disk.wrapper 一样吗?还是有其他事情发生?
    • 是的,就是这么简单。 cache_disk.wrapper = cache_disk() 偶数。
    • 虽然现在想多了,但最常见的形式是什么?那应该是外层。所以可能是倒退的,这需要更多的工作来设置分配。
    【解决方案2】:

    如果你想要默认值,你需要调用函数,它返回一个装饰器:

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

    【讨论】:

      猜你喜欢
      • 2021-07-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-24
      • 2020-02-29
      • 2020-04-28
      相关资源
      最近更新 更多