写了这样一段代码:
[i(4) for i in [(lambda y: print('y=', y, '; x=', x, ' ; n + x = ', y + x)) for x in range(10)]]
发现输出如下:
y= 4 ; x= 9 ; n + x = 13
y= 4 ; x= 9 ; n + x = 13
y= 4 ; x= 9 ; n + x = 13
y= 4 ; x= 9 ; n + x = 13
y= 4 ; x= 9 ; n + x = 13
y= 4 ; x= 9 ; n + x = 13
y= 4 ; x= 9 ; n + x = 13
y= 4 ; x= 9 ; n + x = 13
y= 4 ; x= 9 ; n + x = 13
y= 4 ; x= 9 ; n + x = 13
修改了一下:
import functools
[f(4) for f in [functools.partial(lambda x, y: print('y=', y, '; x=', x, ' ; y + x = ', y + x), y) for y in range(10)]]
输出如下:
y= 4 ; x= 0 ; y + x = 4
y= 4 ; x= 1 ; y + x = 5
y= 4 ; x= 2 ; y + x = 6
y= 4 ; x= 3 ; y + x = 7
y= 4 ; x= 4 ; y + x = 8
y= 4 ; x= 5 ; y + x = 9
y= 4 ; x= 6 ; y + x = 10
y= 4 ; x= 7 ; y + x = 11
y= 4 ; x= 8 ; y + x = 12
y= 4 ; x= 9 ; y + x = 13
不知道为什么会有这样的差异,请指教
你問的這個問題不是那麼好理解, 不過我慢慢說看看能接受多少。
第一段 code
首先我們看到你寫的第一段 code:
我們先專心看內層的 list comprehension:
這段我們可以寫成一段等價的 code:
我們隨意地來測試一下:
希望大家看到這裡可以接受兩者除了一個用 lambda funciton 一個用 normal function 但是其實行為上是一致的。
接著請大家仔細看上面那段等價的 code, 你想到了甚麼呢? 沒錯! decorator 裡面會出現的 閉包(closure) !! 在這裡
x
不就是 free variable 嗎? 所以x
並不會被綁死在ld
中, 他參考到一個非全域的變數x
。我要說的是, 製造出來的 10 個 function 全部都參考到同一個x
,for x in range(10)
很容易誤導大家, 以為有十個不同的x
然後製造了 10 個不同的 function。其實你跟我都明白, 這裡只有一個x
變數, 只是他的值在改變, 但是說到底x
就那麼一個。為了避免空口說白話, 我證明我說的給大家看:
好, 那
x
的值在製造完之後究竟是多少呢?沒錯, 是 9 !, 所有所有製造出來的 function 全部都會參考到這個
x
, 所以他們的x
值就是 9 !所以, 出現這個結果也就不意外了:
第二段 code
接著我們來看第二段 code (一樣 focus 在內層):
partial(func, a)
會凍結func
的第一個引數(會綁定 a 值)所以上面這段 code 會從 0~9 凍結這個 lambda function 的第一個引數, 這邊不同於 free variables, 這裡不是讓第一個引數
x
參考到同一個人, 而是直接綁死(代定) 0~9, 所以這裡每一個製造出來的 functions 全部都不一樣, 且可以當成 x 指定為 0~9。經過上述講解, 應該大致可以明白兩者不同之處了。
結論
partial
會直接凍結引數, 使變數代入定值一般的 function 會直接參考到 free variable 而不是代入定值
我回答過的問題: Python-QA