Python延遲繫結問題原理及解決方案

2022-10-04 13:51:36 字數 1752 閱讀 9529

延遲繫結出現在閉包問題中。下面我們看乙個閉包的例子:

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 輸出結果不是我們想的...