2012-08-29 46 views
8

我剛剛學會了python @ decorator,它很酷,但很快我發現我的修改後的代碼出現了奇怪的問題。Python關閉函數丟失外部變量訪問

def with_wrapper(param1): 
    def dummy_wrapper(fn): 
     print param1 
     param1 = 'new' 
     fn(param1) 
    return dummy_wrapper 

def dummy(): 
    @with_wrapper('param1') 
    def implementation(param2): 
     print param2 

dummy() 

我調試它,它在打印參數1

UnboundLocalError: local variable 'param1' referenced before assignment 

拋出異常,如果我刪除param1 = 'new'這一行,沒有任何修改操作上的變量,從外部作用域(鏈接到新的對象),這個例程可能工作。

這是否意味着我只做了一個外部作用域變量的副本,然後進行修改?


感謝德爾南,這是至關重要的。從這裏 可能的答案: What limitations have closures in Python compared to language X closures?

類似代碼:

def e(a): 
    def f(): 
     print a 
     a = '1' 
    f() 
e('2') 

而且也是這似乎以前討厭的全局變量:

a = '1' 
def b(): 
    #global a 
    print a 
    a = '2' 
b() 

通過添加全球符號,它是固定的。 但是關閉,沒有找到這樣的符號。 感謝unutbu,Python 3給了我們非本地

我知道從上面直接訪問外層變量是隻讀的。 ,但看到前面的閱讀變量(print var)也受到影響會有點不舒服。

+0

的[可能重複什麼限制有在Python閉包相比,語言X倒閉?](http://stackoverflow.com/questions/141642/what-limitations-have-closures-in-python-compared-to-language-x-closures) – delnan

+0

這有絕對的無關與裝飾btw。 – delnan

+0

是的,這發生在關閉。 這樣的: 高清E(一): DEF F(): 打印一個 A = '1' F() E( '123') –

回答

11

當Python解析的函數,它注意到只要找到在賦值的左手側所使用的變量,如

param1 = 'new' 

它假定所有這些變量是本地的功能。 所以,當你用前面

print param1 

這個任務,因爲Python沒有在當時執行打印語句這個局部變量的值,就會發生錯誤。


在Python3,你可以通過聲明param1是外地解決這個問題:

def with_wrapper(param1): 
    def dummy_wrapper(fn): 
     nonlocal param1 
     print param1 
     param1 = 'new' 
     fn(param1) 
    return dummy_wrapper 

在Python2你不得不求助於一招,如通過參數1列表中(或一些其他可變對象):

def with_wrapper(param1_list): 
    def dummy_wrapper(fn): 
     print param1_list[0] 
     param1_list[0] = 'new' # mutate the value inside the list 
     fn(param1_list[0]) 
    return dummy_wrapper 

def dummy(): 
    @with_wrapper(['param1']) # <--- Note we pass a list here 
    def implementation(param2): 
     print param2 
+0

什麼是「修復」這個好辦法嗎? – Silox

+1

...在分配後放置'print'語句? – kindall

+0

感謝您的解釋。但我不知道爲什麼param1 ='new'重新分配外部參數,而是創建一個局部變量。 –

0

您在函數中分配了param1,這使得param1一個局部變量。但是,它在打印時尚未分配,因此出現錯誤。 Python不會回退尋找外部作用域中的變量。

+0

_print param1_說明的一個例子中,在真實的代碼,在任何的param1引用的param1 = XX存在時禁止 –

1

如果你想從在Python 2.x的外部範圍,然後使用全球捕獲變量也是一種選擇(與通常的附帶條件 - 但方便的臨時情況或探索性的代碼)。

而下面將拋出(內內外圍一號的分配使得本地和if條件,因此無界):

def outer(): 
    outer1 = 1 
    def inner(): 
     if outer1 == 1: 
      outer1 = 2 
      print('attempted to accessed outer %d' % outer1) 

這不會:

def outer(): 
    global outer1 
    outer1 = 1 
    def inner(): 
     global outer1 
     if outer1 == 1: 
      outer1 = 2 
      print('accessed outer %d' % outer1) 
相關問題