2011-11-08 39 views
6

這個問題是關於a question about Python variable scope的後續行動。其他問題q1q2answers可以在SO上找到,甚至更多。 官方Python documentationPEP 3104應該解釋的細節,但他們似乎不完全自我解釋給我。Python的非本地依賴於層次結構的級別?

我試圖解決的主題是通過將代碼向上/向下移動一層的層次結構來重構包含nonlocal/global的代碼。

什麼我不明白是這句話從Python參考的意義:

Names listed in a nonlocal statement, unlike to those listed in a global statement, must refer to pre-existing bindings in an enclosing scope (the scope in which a new binding should be created cannot be determined unambiguously).

鑑於全球範圍內將以下代碼:

var = 0 
def outer(): 
    global var     # line A 
    var = 1 
    def inner(): 
     nonlocal var   # line B 
     var = 2 

     print('inner:', var) 

    inner() 
    print('outer:', var) 

outer() 
print('main:', var) 

執行引發錯誤:

SyntaxError: no binding for nonlocal 'var' found 

該代碼工作(使用不同的語義,當然,如果有一個線A註釋:

inner: 2 
outer: 2 
main: 0 

或線B被註釋:

inner: 2 
outer: 1 
main: 1 

然而,在上面的例子中,由於nonlocal應該結合VAR到「封閉範圍「,我會預料到行A將外部/ var綁定到全局範圍,然後行B查找外部/ var,並將內部/ var重新綁定到global/var。相反,它似乎根本找不到它(由於A線的重新綁定,我想),並提出錯誤。

期望的結果我的預期是:

inner: 2 
outer: 2 
main: 2 

這是在Python作用域的頭腦的混亂狀態只是一個例子?

或者,使這個建設性的問題:

  • 試問,這樣的例子在某種程度上被寫入,它不無論在哪個級別的功能所在(其與nonlocal,反之亦然交換global )?
  • 如果函數駐留在中間級別和未知級別,那麼outer()的作者如何更改代碼,即最外層(在本例中爲全局)級別和級別都不必觸及的代碼? -

在我對語言的謙卑理解中,像這樣的構造(依賴於閉包)只是可以避免的。其他人已經建議使用其他語言功能(classes,func attrs)來實現這種上下文敏感性。

+0

全局和局部變量在Python中有着根本性的不同。 'nonlocal'語句只能引用一個封閉範圍的局部變量,而不能引用全局變量 - 這就是'global'的用處。 「全球」和「非本地」背後的概念有很大不同。你目前的狀態應該是一個問題的論點是完全構建的。我的答案是:不要使用全局變量,也不要使用'global',並且所有提到的「問題」(以及其他一些問題)都將消失。 –

+0

雖然我通常同意避免使用全局變量,但其他人似乎發現這個概念非常有用,Python提供了'global'關鍵字,Py3k甚至添加了'nonlocal'。我試圖瞭解他們聯合使用的含義。 – cfi

+1

「...... Py3k甚至增加了一個」nonlocal「。」 'nonlocal'旨在使閉包更有用。它與全局變量無關。 –

回答

6

globalnonlocal並不意味着合併。他們有不同的含義:

  • global意味着名字在模塊級
  • nonlocal存在意味着名字在外部詞法函數範圍

你所得到的原始異常的原因是因爲存在你告訴Python var是非本地的(意思是它在外部函數定義中),但是沒有函數級綁定對於任何外部函數定義中的var,因爲你告訴Python var是全球性的外部功能。

+0

「全局和非本地並不意味着組合」,這正是我的問題:如果不是,那麼重構代碼會變得更加困難。考慮到最內層的函數也使用'nonlocal'和直接的周邊函數。如果周圍的函數改變綁定到'global',那麼最內層的函數也必須改變。但是,唉,隨着手頭的語法,我沒有看到另一種方式。 (但要使用類包裝等) – cfi

+0

我明白你的觀點,但如果你正在將閉包重構爲非閉包,那麼在我看來,這似乎不是一個不合理的工作量。 –

0

How can such an example be written in a way that it does not matter at which level a function resides (having to exchange global with nonlocal and vice versa)?

函數所處的級別無關緊要。它只是變量駐留在哪個層次上。

If the functions reside at an intermediate, and unknown level of hierarchy, how could the author of outer() change the code that neither the outermost (in this case global) level, nor the inner() level have to be touched?

你問是否有可能用於在中間電平的功能,通過在其代碼改變的東西,以使在一個內部函數的變量在全局範圍或東西交替改變的東西外部函數的局部範圍。這似乎是一個非常奇怪的事情,能夠做到。

+0

我的觀點是關於重構:如果中間函數和它的內部函數一起移動了一個較低的級別,即使它的直接環境函數也會使用這個變量,'global'中的'nonlocal'也不得不改變。嗯,我開始認爲我選擇了一個不好的例子來詳細說明這個語法/範圍的問題。 – cfi

+0

@cfi我只是想確定我明白你的意思是:「如果中間函數和它的內部函數一起移動了一個低一級」。最初,'var'和'outer'都在另一個函數的塊中,因此'outer'和'inner'都使用'nonlocal var'。通過將「中間函數與其內部函數一起降低」一起移動,您的意思是將'var'和'outer'移近全球範圍?如果這個'var'和'outer'的新範圍是全局範圍,那麼你必須將'outer'和'inner'中的'nonlocal var'改爲'global var'? – user42768