2011-03-28 76 views
9

我想對Python 3源代碼中的作用域執行一些分析,我被困在nonlocal聲明語句如何在類定義內工作。按照我的理解,類定義在一個新的名字空間(調用它的字典)中執行它的主體,並將類名綁定到類型(name,bases,dict)的結果。非局部x應該工作,只要它引用了一個變量,該變量被綁定在封閉非局部範圍內的某處。在類定義中的Python nonlocal聲明

由此我想到下面的代碼編譯和運行:

class A: 
    v = 1 
    class B: 
     nonlocal v 
     v = 2 

但這種失敗

SyntaxError: no binding for nonlocal 'v' found 

,而下面的代碼運行完美

def A(): 
    v = 1 
    class B: 
     nonlocal v 
     v = 2 

誰能解釋函數定義的關閉與類定義之間的區別在哪裏?

+0

更多研究 - 在最後的代碼示例中,A中的locals()是{v:1},而B中的{v: 2,'__module__'':''__main__'','__locals__':{...}} – Andyrooger 2011-03-29 00:42:24

回答

10

詞法範圍只適用於函數名稱空間,否則在類中定義的方法將能夠「查看」類級屬性(這是通過設計 - 這些屬性必須作爲方法內的self的屬性來訪問)。

導致類級別變量被方法引用忽略的相同限制也使nonlocal關鍵字無法發揮其魔力。 (global確實工作,因爲它不依賴於詞法範圍機制)

+0

謝謝,這是有道理的。我曾經假設有一些非常基本的堆棧形式,對於每個級別都是一樣的。注意到可編輯的模塊文檔改變了我的想法,但我並不真正瞭解發生了什麼,或者爲什麼直到您的答案。 – Andyrooger 2011-03-29 01:50:58

4

Python處理類和函數定義的方式不同。例如,您的A.v不是A的變量,而是它的一個屬性。因此,由類創建的命名空間不是一個範圍。我不驚訝nonlocal不正確,因爲你正在嘗試使用它。

+0

感謝您的回覆。因此,函數作用域在運行時創建,而不是在定義時創建。由於類定義的主體是,我假設,立即在一個不同的名稱空間中執行,這是否不僅僅爲執行期間創建一個範圍? - 我想知道這是否出於同樣的原因內部類無法訪問外部類的屬性... – Andyrooger 2011-03-29 01:00:46

+0

它確實創建了一個臨時範圍,但它是一種不同的*種類的範圍。編譯器在決定哪些屬性可見時使用不同的規則(既可用於內部作用域的引用,也可用於寫入外部作用域)。 – ncoghlan 2011-03-29 01:43:28