2016-09-20 83 views
0

说我有一个功能,看起来像这样:使用装饰带来变数成装饰功能的命名空间

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 

对于我的应用程序它会这样可以更好地定义函数。还有其他方法,但是更多的代码将不得不被添加到每个函数的主体中。

+1

*为什么*你想这样做?你试图解决的实际问题是什么?这对我来说似乎是一个难以理解的代码。 – jonrsharpe

+1

密切相关:[获取要在with语句中执行的命令块](http://stackoverflow.com/q/12485837);那里的解决方案也适用于装饰器,因为'arg3'只能作为全局来使用。 –

+0

我试图让用户定义一个常微分方程系统作为一系列功能,以与现有软件类似的方式进行整合。 – pbreach

回答

0

这是在哈克侧一点点,但这implmentation装饰似乎你想要做什么。 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 
+0

这适用于我!使用'exec'看起来确实很不好,但这个问题也有点不顺手。将等待看看是否有其他答案出现。 – pbreach

+0

还有更多的方法可以做到,比如修改装饰函数的字节码。有一个例子在[answer](http://stackoverflow.com/a/3454053/355230)中做了这样的事情,以解决一个关于自动添加一个“self”参数给类的方法的问题(尽管不一定使用装饰器)。这种方法的一个优点是结果将会因为它太低而跑得更快。 – martineau

0

你可以那样做

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)) 

让你不依附于任何名称,只要你想,你可以申请尽可能多的装饰。所以如果你想添加更多的装饰器,它会工作。例如

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

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

# Output would be 12(1 + 2 + 3 + 3 + 3)