2012-03-23 66 views
1

以下(荒誕而是說明性的)代碼的工作通過突變在封閉函數定義的列表作爲預期:對象可變性對Python的作用域有什麼影響?

def outside1(): 
    l = list('abcd') 
    def inside(a): 
     print "Before - %i: %r" % (id(l), l) 
     l.append(a) 
     print "After - %i: %r\n" % (id(l), l) 
    return inside 

f = outside1() 
[f(c) for c in 'efgh'] 

該代碼也可以表示,在一個封閉的範圍限定的不可變的是封閉範圍內的訪問:

def outside2(): 
    t = tuple('abcd') 
    def inside(): 
     print "%i: %r" % (id(t), t) 
    return inside 

outside2()() 

但是這個失敗local variable 't' referenced before assignment

def outside3(): 
    t = tuple('abcd') 
    def inside(a): 
     print "Before - %i: %r" % (id(t), t) 
     t = t + (a,) 
     print "After - %i: %r\n" % (id(t), t) 
    return inside 

f = outside3() 
[f(c) for c in 'efgh'] 

可有人è xplain這裏發生了什麼?我的第一個猜測是,我可以進行變異,但不能指定爲封閉範圍,但是如果outside2工作,我至少應該在打印聲明之前工作

回答

6

Python在編譯時靜態檢測名稱範圍:分配給函數內部的名稱成爲該函數的本地名稱。太行

t = t + (a,) 

呈現t本地inside(),並tinside()任何查詢將嘗試查找的inside()一個局部變量。當上面的一行很好時,t還不存在,因此出現錯誤。

在Python 3.x中,您可以通過顯式聲明tnonlocal解決這一問題:

def outside3(): 
    t = tuple('abcd') 
    def inside(a): 
     nonlocal t 
     print("Before - %i: %r" % (id(t), t)) 
     t = t + (a,) 
     print("After - %i: %r\n" % (id(t), t)) 
    return inside 

這一切是完全無關的可變性。您使用列表的示例不會重新指定名稱l,而使用元組的示例確實爲重新指定t;這是重要的區別,而不是可變性。

+0

「Python在編譯時靜態檢測名稱的範圍」謝謝,這是簡短的答案; py3k的提示是一個不錯的獎勵。 – Finn 2012-03-23 14:17:53

3

可變性對範圍沒有影響。

問題是,分配給不在當前範圍內的變量會創建該變量,而僅僅讀取該變量則不會。

+0

Downvoter:你在這裏有什麼不同意? – Marcin 2012-03-23 14:24:53

+1

+1這是正確的答案 – newacct 2012-03-23 18:50:22

1

Marcin是對的。可變性對範圍完全沒有影響。

你需要了解的是,在第一個例子,而你是「突變列表中的」指向l,你只是讀變量l,然後調用它的一些方法(.append())。這與您在閱讀變量t的第二個示例中完全相同。

在這兩種情況下,您都沒有分配給外部範圍的變量,只是簡單地讀取它。可變性僅僅意味着你可以改變變量所指向的東西,從而以這種方式共享變化。但從變量和範圍來看,絕對沒有區別。

在第三個示例中,您將分配給變量t。這是不同的。 Python 2.x無法通過global將全局變量分配給外部變量。 Python 3.x有nonlocal允許你這樣做。需要注意的是可變性無關,用它做:如果你試圖分配到(而不是僅僅發生變異的對象指向)在你的第一個實例變量l,你會碰到同樣的問題:

def outside1(): 
    l = list('abcd') 
    def inside(a): 
     print "Before - %i: %r" % (id(l), l) 
     l = [1,2,3] 
     print "After - %i: %r\n" % (id(l), l) 
    return inside 
相關問題