2016-09-20 78 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)