延遲繫結出現在閉包問題中。下面我們看乙個閉包的例子:
def (n):
def mul(x):
return n*x
return mul
double = gen_mul(2)
doubled_value = double(6)
可以看出滿足閉包的幾點:
閉包的優點:
閉包的缺點:
當然缺點可以通過人為避免。
現在我們來看看另乙個會引出延遲繫結的例子:
def multipliers():
return [lambda x : i * x for i in range(4)]
print([m(2) for m in multipliers()]) # [6,6,6,6]
上邊的例子會輸出[6,6,6,6],而不是我們預期的[0,2,4,6]。
這就是延遲繫結導致的結果。具體過程我們可以來分析下:
執行第三行時,會先執行multipliers函式,然後執行函式中的列表解析式。在每一次迭代的時候都會生成乙個匿名函式(這裡只是定義)作為元素。然後回到第三行,遍歷返回的列表中的匿名函式,傳入引數2並執行。此時函式類似於這樣:
def noname(x):www.cppcns.com
return i * x
bineldes
我們知道python查詢變數的作用域鏈的順序依次為legb:
區域性變數(l)->外部函式中的區域性變數(e)->全域性變數(g)->內建變數(b)
非常重要的一點我們需要知道:python的作用域在編譯時就已經形成了,而不是在執行時,函式的作用域與其被呼叫的位置無關。
那麼在本例中,上面的noname函式體中的i從何而來呢?當然首先會到mubineldesltipliers函式的區域性變數中去尋找。此時i的值已經為3,所以出現這種讓人」費解」的現象。
那麼現在我們既然已經知道了原因,www.cppcns.com那麼要怎樣解決呢?
我們可以將迭代的i值直接注入到匿名函式的函式體中,這裡給出兩種方法:
通過為引數設定預設值,這是因為在編譯時就會計算確定預設值:
def multipliers_ch1():
return [lambda m,x=i : m * x for i in range(4)]
通過內建函式partial:
from functools import partial
def multipliers_ch2():
retu [partial(lambda m,x : m * x,i) for i in range(4)]
利用生成器的延遲計算:
def multipliers_ch3():
for m in range(4):
yield lambda x: m * x
partial及生成器的內容會在以後分享。
執行結果
print([m(2) for m in multipliers_ch1()]) # [0,2,4,6]
print([m(2) for m in multipliers_ch2()]) # [0,2,4,6]
print([m(2) for m in multipliers_ch3()]) # [0,2,4,6]
注:自由變數:指未在本地作用域中繫結的變數,我們可通過訪問函式的code屬性進行檢視:
fun.code.co_freevars
legb: 可看該部分解釋
本文標題: python延遲繫結問題原理及解決方案
本文位址:
python 延遲繫結(late binding)
usr bin env python3 coding utf 8 a test module author zhang shuai defoperator return lambda n n m for m in range 6 print o 3 for o in operator 這是由於閉包函...
Python中的延遲繫結
延遲繫結出現在閉包問題中。下面我們看乙個閉包的例子 def gen mul n defmul x return n x return mul double gen mul 2 double value double 6 print double value 可以看出滿足閉包的幾點 閉包的優點 閉包的...
python 高階之路 繫結延遲
看看下面一題,試著寫出自己的答案。defmultipliers return lambda x i x for i in range 4 print m 2 for m in multipliers print type multipliers res 6,6,6,6 list 輸出結果不是我們想的...