溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

解決Python延遲綁定問題

發(fā)布時(shí)間:2020-08-04 13:57:29 來源:億速云 閱讀:198 作者:小豬 欄目:開發(fā)技術(shù)

小編這次要給大家分享的是解決Python延遲綁定問題,文章內(nèi)容豐富,感興趣的小伙伴可以來了解一下,希望大家閱讀完這篇文章之后能夠有所收獲。

延遲綁定出現(xiàn)在閉包問題中。下面我們看一個(gè)閉包的例子:

def (n):
  def mul(x):
    return n*x
  return mul
double = gen_mul(2)
doubled_value = double(6) 

可以看出滿足閉包的幾點(diǎn):

  • 有內(nèi)部函數(shù)
  • 內(nèi)部函數(shù)引用了外部函數(shù)中的自由變量
  • 內(nèi)部函數(shù)被返回
     

閉包的優(yōu)點(diǎn):

  • 可以避免使用全局變量
  • 可以持久化變量,達(dá)到靜態(tài)變量的作用
     

閉包的缺點(diǎn):

  • 可能會(huì)消耗大量的內(nèi)存
  • 可能會(huì)導(dǎo)致內(nèi)存泄漏

當(dāng)然缺點(diǎn)可以通過人為避免。

現(xiàn)在我們來看看另一個(gè)會(huì)引出延遲綁定的例子:

def multipliers():
  return [lambda x : i * x for i in range(4)]
print([m(2) for m in multipliers()]) # [6,6,6,6]

上邊的例子會(huì)輸出[6,6,6,6],而不是我們預(yù)期的[0,2,4,6]。

這就是延遲綁定導(dǎo)致的結(jié)果。具體過程我們可以來分析下:
執(zhí)行第三行時(shí),會(huì)先執(zhí)行multipliers函數(shù),然后執(zhí)行函數(shù)中的列表解析式。在每一次迭代的時(shí)候都會(huì)生成一個(gè)匿名函數(shù)(這里只是定義)作為元素。然后回到第三行,遍歷返回的列表中的匿名函數(shù),傳入?yún)?shù)2并執(zhí)行。此時(shí)函數(shù)類似于這樣:

def noname(x):
return i * x

我們知道Python查找變量的作用域鏈的順序依次為L(zhǎng)EGB:

局部變量(L)->外部函數(shù)中的局部變量(E)->全局變量(G)->內(nèi)置變量(B)

非常重要的一點(diǎn)我們需要知道:Python的作用域在編譯時(shí)就已經(jīng)形成了,而不是在運(yùn)行時(shí),函數(shù)的作用域與其被調(diào)用的位置無關(guān)。

那么在本例中,上面的noname函數(shù)體中的i從何而來呢?當(dāng)然首先會(huì)到multipliers函數(shù)的局部變量中去尋找。此時(shí)i的值已經(jīng)為3,所以出現(xiàn)這種讓人”費(fèi)解”的現(xiàn)象。

那么現(xiàn)在我們既然已經(jīng)知道了原因,那么要怎樣解決呢?

我們可以將迭代的i值直接注入到匿名函數(shù)的函數(shù)體中,這里給出兩種方法:

通過為參數(shù)設(shè)置默認(rèn)值,這是因?yàn)樵诰幾g時(shí)就會(huì)計(jì)算確定默認(rèn)值:

def multipliers_ch2():
return [lambda m,x=i : m * x for i in range(4)]

通過內(nèi)置函數(shù)partial:

from functools import partial
def multipliers_ch3():
  return [partial(lambda m,x : m * x,i) for i in range(4)]

利用生成器的延遲計(jì)算:

def multipliers_ch4():
  for m in range(4):
    yield lambda x: m * x

partial及生成器的內(nèi)容會(huì)在以后分享。

運(yùn)行結(jié)果

print([m(2) for m in multipliers_ch2()]) # [0,2,4,6]
print([m(2) for m in multipliers_ch3()]) # [0,2,4,6]
print([m(2) for m in multipliers_ch4()]) # [0,2,4,6]

注:

自由變量:指未在本地作用域中綁定的變量,我們可通過訪問函數(shù)的code屬性進(jìn)行查看:

fun.code.co_freevars

看完這篇關(guān)于解決Python延遲綁定問題的文章,如果覺得文章內(nèi)容寫得不錯(cuò)的話,可以把它分享出去給更多人看到。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI