1. 什麼是閉包, 閉包必須滿足以下3個條:
2. 閉包的優點
def
add(a)
:def
add(b)
:return a + b
return add
ad(2)(
2)# 計算2+2的值, 用類實現的話, 相對麻煩
# 閉包使用nonlocal
deftester
(start)
: state = start
defnested
(label)
:nonlocal state
print
(label, state)
state +=
1return nested # 結合nonlocal使用的話還能實現意想不到的效果, 初始情況下給start傳入不同的值, 會儲存到不同的物件
deftest
(start)
:global state
state = start
defnest
(label)
:global state
print
(label, state)
state +=
1return nest # global的話初始情況下給start無論傳入什麼值, 操作的始終都是乙個物件, 達不到類實現的效果
# 類實現nonlocal的效果
class
myclass
:def
__init__
(self, start)
: self.start = start
defnest
(self, label)
:print
(label, self.start)
self.start +=
1
3. 閉包的延遲繫結def
multipliers()
:return
[lambda x : i*x for i in
range(4
)]print
([m(2)
for m in multipliers()]
)# 列印結果是[6, 6, 6, 6], 而不是[0, 2, 4, 6]
# 原因: i不僅僅控制著迴圈次數, 而且還在為i*x的i提供引用的值, 當python直譯器執行的時候, 呼叫multipliers()的時候, 只會先定義lambda匿名函式, 但是卻會直接執行後面的for迴圈, 當lambda被呼叫的時候, i已經指向了4, 這就是延遲繫結的特性(python中非區域性變數繫結的是記憶體位址, 區域性變數繫結的是值)
4. 延遲繫結的解決辦法
方法一:
def
multipliers()
:return
[lambda x, i=i: i*x for i in
range(4
)]print
([m(2)
for m in multipliers()]
)# 列印結果是[0, 2, 4, 6]
# python直譯器在定義函式時, 遇到關鍵字引數, 就必須初始化引數, 此時後面的for迴圈每迴圈一次, 前面的關鍵字引數i就需要找一次引用物件, for迴圈每迴圈一次結果i都會被i這個關鍵字引數指向, 這個指向的是值, 不是空間
方法二: python生成器
deff1(
):for i in
range(4
):yield
lambda x: x * i
print
(list
((m(2)
for m in f1())
))# list()中是()這個是生成器的推導式(這種方法可以簡單的呼叫上面的函式內部的生成器)
總結: 延遲繫結只是一種現象, 一種特徵, 並不是本質 Python 知識點 閉包延遲繫結
在乙個函式內部定義另乙個函式,外部的函式為外函式,內部的函式為內函式,內函式裡運用了外函式的臨時變數,並且外函式的返回值是內函式的引用。這就形成了乙個閉包。通常情況下,乙個函式執行結束後,函式內部的所有東西都會被釋放掉,區域性變數也會消失。但是如果外函式在結束時發現自己的臨時變數會在內函式中用到時,...
Python的閉包的後期繫結問題
def multi return lambda x i x for i in range 4 print m 3 for m in multi 正確答案是 9,9,9,9 而不是 0,3,6,9 產生的原因是python的閉包的後期繫結導致的,這意味著在閉包中的變數是在內部函式被呼叫的時候被查詢的,...
python 閉包 python 閉包
閉包 因為python中函式也可以當作物件,所以如果出現當我們返回乙個函式,而該函式含有外部變數的時候就形成了閉包。閉包的特點 是個巢狀函式 可以獲得非區域性的變數 將函式當作物件返回 看乙個例子會更易理解 def make printer msg msg hi there def printer ...