2015-08-26 19 views
2

NameError爲什麼會這樣:使用裝飾產生一個定義的函數

def fn(proc, *args, **kwargs): 
    cache = proc.cache = {} 
    def cached_execution(cache, *args, **kwargs): 
     if proc in cache: 
      if args in cache[proc]: 
       return cache[proc][args] 
     res = proc(args) 
     cache[proc] = {args: res} 
     return res 
    return cached_execution(cache, proc, *args, **kwargs) 

@fn 
def cached_fibo(n): 
    if n == 1 or n == 0: 
     return n 
    else: 
     return cached_fibo(n-1) + cached_fibo(n-2) 

print cached_fibo(100) 

拋出這樣一個異常:

NameError: global name 'cached_fibo' is not defined

我失去了什麼根本性的概念?

(概念上,**kwargs僅供裝飾使用,不用於檢索緩存結果,但不用擔心)。

+0

你期待的代碼是什麼? –

回答

3

裝飾器應該返回一個函數,而不是結果調用一個函數。 但是這會導致我們犯下一個錯誤:當你通過cacheproccached_execution函數時,它們落在*args之內,然後轉到proc。這沒有意義。只要讓cacheproc被內部方法內捕獲:

def fn(proc, *args, **kwargs): 
    cache = proc.cache = {} 
    def cached_execution(*args, **kwargs): 
     if proc in cache: 
      if args in cache[proc]: 
       return cache[proc][args] 
     res = proc(*args) 
     cache[proc] = {args: res} 
     return res 
    return cached_execution 

另一個問題是:你不拆包args。您應該撥打proc(*args)而不是proc(args)(上面已經修復)。

+0

我壞我的壞。我正在返回函數調用而不是函數。愚蠢的錯誤。但謝謝指出! – user2290820

+3

請注意,這仍然不實際工作。它會運行,我的意思是,但是因爲它每次都會拋開進程緩存('cache [proc] = {args:res}'),所以你沒有獲得任何memoization的好處。你應該使用'cache.setdefault(proc,{})[args] = res'。 – DSM

+0

是沒有解決這個問題。我對第一個問題深表關切。感謝您指出。 – user2290820

1

包裝看起來有點畸形。下面是一個更新版本:

def fn(proc): 
    cache = proc.cache = {} 

    def cached_execution(*args, **kwargs): 
     if proc in cache: 
      if args in cache[proc]: 
       return cache[proc][args] 
     res = proc(args[0]) 
     cache[proc] = {args: res} 
     return res 
    return cached_execution 

你試圖運行封裝內包裝函數沒有返回它來運行的功能,引起問題。

下一個問題是,您提供的說法是在proc(args)當你只想要第一個元組*args的列表,所以需要轉化爲proc(args[0])

+0

我需要將我的頭包裹在包裝器中的包裝函數中! – user2290820

相關問題