使用装饰器将变量带入装饰函数名称空间

时间:2016-09-20 17:13:41

标签: python function namespaces python-decorators

假设我有一个看起来像这样的函数:

def func(arg1, arg2):
    return arg1 + arg2 + arg3

我想使用传递给装饰器的参数引入arg3。这是可能的,如果可以的话,会怎样做?

我已经尝试了这个,建议here能够将参数传递给装饰器:

from functools import wraps

def addarg(arg):
    def decorate(func):
        arg3 = arg
        @wraps(func)
        def wrapped(*args):
            return func(*args)
        return wrapped
    return decorate

@addarg(3)
def func(arg1, arg2):
    return arg1 + arg2 + arg3

if __name__ == "__main__":
    print(func(1, 2))

但是我得到了这个错误(可以理解):

Traceback (most recent call last):
  File "C:/Users/pbreach/Dropbox/FIDS/PhD/Code/anemi3/utils.py", line 19, in <module>
    print(func(1, 2))
  File "C:/Users/pbreach/Dropbox/FIDS/PhD/Code/anemi3/utils.py", line 9, in wrapped
    return func(*args)
  File "C:/Users/pbreach/Dropbox/FIDS/PhD/Code/anemi3/utils.py", line 16, in func
    return arg1 + arg2 + arg3
NameError: name 'arg3' is not defined

对于我的应用程序,能够以这种方式定义函数会更好。还有其他方法,但是必须将更多代码添加到每个函数的主体中。

2 个答案:

答案 0 :(得分:0)

你可以这样做

DECLARE @ResultAmount int = 243

SELECT @ResultAmount - (@ResultAmount%50)

这样您就不会附加任何名称,您可以根据需要应用尽可能多的装饰器。因此,如果你想添加更多装饰器,它将起作用。例如

from functools import wraps

def addarg(arg):
    def decorate(func):
        @wraps(func)
        def wrapped(*args):
            return func(*args, arg)
        return wrapped
    return decorate

@addarg(3)
def func(arg1, arg2, *args):
    return arg1 + arg2 + sum(args)


if __name__ == "__main__":
     print(func(1, 2))

答案 1 :(得分:0)

这有点在黑客方面,但装饰者的这个实施似乎做你想要的。必须使arg3变量显示为全局变量,因为它在从func()的定义生成的字节代码中被引用为一个,因此它不是真正被认为是函数参数 - 但是它没有'在这种情况下似乎很重要。

from functools import wraps

def addarg(arg):
    def decorate(func):
        @wraps(func)
        def wrapped(*args):
            global_vars, local_vars = {'func': func, 'args': args}, {}
            func.__globals__.update(arg3=arg)
            exec('_result = func(*args)', global_vars, local_vars)
            return local_vars['_result']
        return wrapped
    return decorate

@addarg(3)
def func(arg1, arg2):
    return arg1 + arg2 + arg3

if __name__ == "__main__":
    print(func(1, 2))  # -> 6