2017-09-14 86 views
7

在此代碼:爲什麼不同的變量名稱會得到不同的結果(python2.7)?

results = [] 
for i in [1, 2, 3, 4]: 
    def inner(y): 
     return i 
    results.append(inner) 

for i in results: 
    print i(None) 

的輸出爲 「函數內在0x107dea668」

如果我改變到其他信,例如:

results = [] 
for i in [1, 2, 3, 4]: 
    def inner(y): 
     return i 
    results.append(inner) 

for j in results: 
    print j(None) 

輸出爲「4」


回答

results = [] 
for i in [1, 2, 3, 4]: 
    def inner(y): 
     print "in inner:%s " % id(i) 
     return i 
    results.append(inner) 

# i -> 4 
for i in results: 
    # i -> func inner 
    print "i: %s" % i 
    print "in loop: %s " % id(i) 

    # func inner <===> A 
    # i == A -> return i -> return A, so when call funtion inner, will return itself 
    # print "call: %s" % i(None) 

    print "call: %s" % i(None)(None)(None) 
    print "------------------------------" 

I:在內部4315172208
:4315172208
呼叫功能內在0x101344d70
在循環:在內部4315172208
:4315172208
在內:功能內在0x101344d70

I:在內部4315172328
:4315172328
在內:4315172328
在內:在0x101344de8
在循環函數內4315172328
呼叫:函數內在0x101344de8

I:功能在0x101344e60內
在循環:4315172448
在內:4315172448
在內:4315172448
在內:4315172448
呼叫:函數內在0x101344e60

I:函數內在0x101344ed8
在循環:在內部4315172568
:4315172568
在內:4315172568
在內:4315172568
呼叫:函數內在0x101344ed8

+3

你剛認識的'i' –

+0

有關懶惰的評價:https://stackoverflow.com/questions/42805800/generator-comprehension-different-output-from-list-comprehension –

+0

這是不相關懶惰的評估,這是一個背景問題。懶惰評估只是在需要時評估,而不是在哪裏評估。 –

回答

1

i變量返回inner函數保留它的值,而不是它分配的最後一個上下文。

如果調試代碼,使用inner函數中的斷點,如果在調用函數之前選擇前一幀/上下文(圖中左下角),圖片將變得更清晰。

當您使用i時,它被分配在第二個for內部,因此它將具有一個函數作爲其值(在圖1中用黃色突出顯示)。現在

Figure 1

,如果你使用j,可變i將繼續從以前的背景下其最後的值:在for在列表(圖2)。

Figure 2

1

事實上,當你在結果中使用j時,變量i保持爲4,由於第一次循環後,我保持數字4;

但是,如果您在結果中使用i,那麼我指的是存儲在結果中的函數。在你開始打電話之前,我並不固定。正如@ Jean-FrançoisFabre所言,懶惰的評價。

此外,如果你想內部函數來存儲每個i當來自1-4環,您我應該存儲在相關範圍,使用局部功能;

from functools import partial 

results = [] 
for i in [1, 2, 3, 4]: 
    def inner(i, y): 
     return i 


    results.append(partial(inner, i)) 

for i in results: 
    print(i(None)) 

這會給你的

1 
2 
3 
4 

這是更有意義的結果。

3

您定義的inner函數包含一個自由變量,指向全局變量i。這也許是一個例子像這樣清晰的:

def inner(y): 
    return i 

i = 1 
print inner(None) 

i = 2 
print inner(None) 

它打印1,然後2

在你的第一個例子中,在調用inner的時間,i已經是函數的值,所以當i(即inner)被調用時打印的是什麼。

在第二示例中,在呼叫到inner時,i具有值4,因此這是當j(這是inner)被稱爲什麼被打印。

一個明確的方式來表達你大概想要在這裏是使用部分評估的功能,如另一answer推薦。另一種方法是使用封閉函數來創建閉包。像這樣:

results = [] 
for i in [1, 2, 3, 4]: 
    def outer(k): 
     def inner(y): 
      return k 
     return inner 
    results.append(outer(i)) 

for i in results: 
    print i(None) 

這將打印1至4大概你想要的。

甲小動作有時在Python使用是使用變量的默認值作爲單元格包含一個值:

results = [] 
for i in [1, 2, 3, 4]: 
    def inner(y, i = i): 
     return i 
    results.append(inner) 

for i in results: 
    print i(None) 

這也打印在1至4

相關問題