带有可选参数的装饰器?

时间:2020-08-14 09:01:59

标签: python python-decorators

我看着enter image description here尝试构建一个可以与OR一起使用且不带参数(即可以用@deco@deco(arg1='x',arg2='y')调用的装饰器)。但是我在使用参数时遇到了麻烦:如果我取消注释下面的2条注释行,则会得到UnboundLocalError: local variable 'arg1' referenced before assignment,但是从逻辑上讲,当注释行时也会出现此错误,因为在变量之间未分配任何值。 / p>

def deco(_func=None, *, arg1=False, arg2='default'):
    def outer_wrap(func):
        def inner_wrap(*args, **kwargs):
            # if not arg1:
            #     arg1 = 'blah'
            return 'arg1: '+str(arg1)+', arg2: '+str(arg2)
        return inner_wrap
    if _func is None: # case when @deco is called with arguments
        return outer_wrap
    else: # case without arguments
        return outer_wrap(_func)

@deco
def I(n):
    return n
I(1) 

在这里一定有我所缺少的东西,欢迎您帮助我们理解为什么会发生这种情况。 (我使用的是Python 3.8.3)

编辑 由于以下答案,我还通过添加arg1和arg2作为包装函数的参数来修改了代码:

def deco(_func=None, *, arg1=False, arg2='default'):
    def outer_wrap(func, arg1=arg1, arg2=arg2):
        def inner_wrap( *args, arg1=arg1, arg2=arg2, **kwargs):
            if not arg1:
                arg1 = 'blah'
            return 'arg1: '+str(arg1)+', arg2: '+str(arg2)
        return inner_wrap
    if _func is None:
        return outer_wrap
    else:
        return outer_wrap(_func)

@deco #can add or remove arguments here
def I(n):
    return n
print(I(5))

3 个答案:

答案 0 :(得分:0)

注释掉赋值后,arg1不是内部函数中的 local 变量,因为它是外部函数的参数。

内部函数中的赋值arg1 = 'blah'使局部变量具有相同的名称,从而在下一行更改arg1的含义;现在它是内部函数的局部变量,当if语句的条件为false时,该变量没有赋值,因此Python不再寻找相同名称的其他变量。

此行为在this other Stack Overflow Q&A中有更详细的描述。

答案 1 :(得分:0)

只需完成@ kaya3答案,您就可以代替:

mkdir -p /var/run/mysqld/
chmod 777 /var/run/mysqld/

答案 2 :(得分:0)

这个问题与python中的'Closure'函数有关。闭包是一个函数对象,即使在内存中不存在值时,它也会记住范围内的值。

通过使用arg1=blah,使其成为内部函数的局部变量。要解决此问题,而不是将arg1用作外部函数参数中具有布尔值arg1=False的不可更改对象,可以使arg1成为类型为list,set,dict的可变对象。

例如:

enter code here
def deco(_func=None, arg1=[], arg2='default'):
    def outer_wrap(func):
        def inner_wrap(*args, **kwargs):
            if len(arg1) is 0:
                arg1.append('blah')
            return 'arg1: ' + arg1[0] + ' arg2: ' + str(arg2)
        return inner_wrap
    if _func is None: # case when @deco is called with arguments
        return outer_wrap
    else: # case without arguments
        return outer_wrap(_func)

@deco
def I(n):
    return n
I(1)

您可以在互联网上进一步了解python中的闭包函数。(例如:https://www.openbookproject.net/py4fun/decorator/decorator.html