一個經典的 Python 面試題:
result = [lambda x: x + i for i in range(10)]
print(result[0](10))
問,打印的結果是多少?
19
不止result[0](10)
結果是19,result[1](10)
,result[2](10)
…result[9](10)
全是 19。
爲什麼不是 10,11…19 呢?變量 i 不是從 0 取值到 9 麼,分別再加 10。然鵝既然是面試題, 沒有坑就不好意思流傳的😂。
首先我們看這句話代碼幹了啥:
result = [lambda x: x + i for i in range(10)]
這是一個列表生成式,生成的是一個匿名函數列表。
這裏需要了解一下 Python 中函數的運行機制:
- 遇到函數定義,直接將函數加載到內存而不會執行函數代碼。你可以簡單認爲就是把代碼原封原樣的放到內存中(實際上此時函數會生成一個內存中的對象);
- 只有當調用時纔會實際執行函數。
這裏只是生成了匿名函數的列表而不會實際執行函數代碼,也就是說暫時並沒有生成結果。函數內部的 i 依然是隻是變量,並沒有變成具體的值,因爲此時函數並沒有執行。
只有當函數被調用時纔會實際執行函數代碼,result[0]
提取列表中的第一個匿名函數,在後面加上括號並傳入參數 result[0](10)
纔會實際調用函數,此時纔開始執行函數,纔會去找對應的變量值。
這時候就有一個問題了,i 變量在 for 循環時定義,當 for 循環完成後變量 i 的值已經變成了 9。
所以不管你取列表中的哪個函數來執行,都是同樣的結果。
如果想要結果達到你想要的 10,11…19 的話,可以在循環時就把 i 作爲參數傳進去,而不是直接使用 for 循環中的 i 變量。
result = [lambda x, i=i: x + i for i in range(10)]
print(result[0](10))
上面的代碼,匿名函數增加了一個參數 i,並且把 i 參數的默認值設置爲 for 循環中 i 變量的值。那麼每次循環時,生成的匿名函數就會把當次循環的 i 變量的值記錄到i 參數的默認值。
這樣在後面調用時,匿名函數的 i 參數的默認值都是不同的,結果就會變成 10, 11…19 了。