2014-01-11 63 views
0

我想了解Python 3變量範圍和nonlocal瞭解Python中的非本地3

考慮下面的函數(這只是一個例子):

def build_property(something): 

    def deco(func): 

     def getter(self): 
      return getattr(self, something) 

     def setter(self, value): 
      setattr(self, something, value) 

     return property(getter, setter) 

    return deco 

這不nonlocal工作正常。但是如果現在我想根據something有條件地創建getter和setter,那麼我需要非本地的。

def build_property(something): 

    def deco(func): 

     nonlocal something # This is needed 

     if something.startswith('A'): 
      getter = None 
     else: 
      def getter(self): 
       return getattr(self, something) 

     if something.startswith('B'): 
      setter = None 
     else: 
      def setter(self, value): 
       setattr(self, something, value) 

     return property(getter, setter) 

    return deco 

爲什麼nonlocal需要在一種情況下,而不是在其他?換句話說,爲什麼something如果在第一種情況下正確找到(沒有nonlocal),但在第二個我得到:「UnboundLocalError:本地變量'之前引用的東西'如果nonlocal不存在?

+1

...你的問題是?你沒有*說*錯誤/意外行爲。如果您遇到異常,請在您的問題中提供**完整**回溯。如果您發現意外的行爲,您應*提供1)您期望的行爲和2)您獲得的實際產出。我們不是**算命先生。 – Bakuriu

+0

只是出於求知慾:你的裝飾者的意義何在?你似乎沒有在任何地方使用'func' ... – glglgl

+0

順便說一句,我沒有測試代碼,但我不明白爲什麼它應該在第二種情況下需要,因爲'something'永遠不會分配給。 .. – glglgl

回答

-1
def A(d): 
    outer = object() 
    d["outer"] = outer 
    def B(): 
     print locals() 
     assert d["outer"] is outer #This fails and never reaches 
     inner = object() 
     d=dict()     #this line. 
     print locals() 
    def C(): 
     print locals() 
     assert d["outer"] is outer #This goes on fine. 
     inner = object() 
     print locals() 
    return B,C 

=> b,c = A(dict()) 
=> c() 
-snip, AOK- 
=> b() 
UnboundLocalError: local variable 'd' referenced before assignment 

對不起,我配得上火焰。上面的代碼我很快就寫下來了,這個答案以前就是一堆廢話。

但它是令人驚訝的。我一直認爲python(2.x)是一種完全沒有前瞻性的語言,在最後時刻評估一切...

對不起,現在是脫離主題。

+0

我寫了一些愚蠢的東西,但它是關於保持父範圍的引用,是的。 –

+0

這個答案是不正確的。 'nonlocal'不是一個優化,有必要正確識別變量的創建範圍。 Python 2並不保留所有封閉的本地化,只保留封閉引用的那些 - 與Python 3完全一樣。區別在於,Python 3允許您在不創建新變量的情況下*改變封閉變量的值作爲副作用。'nonlocal'告訴編譯器,儘管分配發生在內部塊中,被修改的變量是在外部塊中創建的變量。 – user4815162342

1

第一張:nonlocal在您編寫的代碼中不是必需的。您不會更改something指向的對象。

第二:有些情況下您需要使用nonlocal。以下是一些代碼,其中nonlocal是必要的。請注意,所有斷言都是正確的(也就是說,它們不引發AssertionError)。

def main(): 
    variable = 1 

    def function(): 
     variable = 2 
    function() 
    assert variable == 1 

    def function(): 
     nonlocal variable 
     variable = 2 
    function() 
    assert variable == 2 

if __name__ == '__main__': 
    main() 

第三:你呈現不產生你要求它做錯誤的代碼。如果我刪除nonlocal行,並調用以下函數,則不會出現錯誤。

build_property('A')(lambda: True) 
build_property('B')(lambda: True) 
build_property('C')(lambda: True)