在廖雪峰的官網上看到乙個很有意思題目。關於閉包的,有興趣的朋友可以看一下, 做一下這個題目,當然需要一點閉包的知識。
下面我簡述一下:
利用閉包返回乙個計數器函式,每次呼叫它返回遞增整數。
# 修改下面這個函式
def createcounter():
def counter():
pass
return counter
# 測試:
countera = createcounter()
print(countera(), countera(), countera(), countera(), countera()) # 1 2 3 4 5
counterb = createcounter()
if [counterb(), counterb(), counterb(), counterb()] == [1, 2, 3, 4]:
print('測試通過!')
else:
print('測試失敗!')
方法一
說實話這題對我來說還是有點難度的,但我嘗試了幾次之後也找到乙個比較track的方法。一開始我是這麼寫的。
def createcounter():
i = 0
def counter(i=i):
i = i+1
return i
return counter
# 執行結果是:1 1 1 1 1
這樣當然是錯的, 因為整數是不可變物件,當你作為引數傳進去時都會建立乙個新的記憶體空間。
這裡邊其實還有很多學問,不是很了解的可以看一下stackoverflow上的這個回答:
雖然失敗了,但也讓我想到乙個track的方法,就是把i換成可變物件。
def createcounter():
i = [0]
def counter():
i[0] = i[0]+1
return i[0]
return counter
# 執行結果是:1 2 3 4 5
ok, 這樣就沒有問題了。但這並不是乙個好的解決方法, 利用可變物件的這個特性有可能會引起變數作用域混亂的。於是我又想到了另一種解決。
方法二另一種方法就是使用generator,在createcounter函式下建立乙個從1開始的整數generator, 然後在cuonter函式中呼叫。
由於generator儲存的是演算法,當呼叫next函式時就可以計算出下乙個的值,直到沒有元素報錯。當然這裡不用擔心,generator可以建立無限集合。
def createcounter():
def inter():
n = 1
while true:
yield n
n = n+1
f = inter()
def counter():
return next(f)
return counter
上面的**中,inter()就是乙個包含從1開始的所有整數的generator。然後在counter裡邊呼叫。每次計算下乙個的值。這樣就可以實現計數的功能。
說到generator,stackoverflow上有乙個回答值得一讀,即使你已經掌握這個也可以讀一下,這個回答應該還是python問答當中排名第一的。
鏈結在這裡:
方法三
def creat_counter():
i=0def counter():
nonlocal i
i=i+1
return i
return counter
學了python這麼久,第一次看到nonlocal這個關鍵字,果然我還是太菜了……
不過從語句上看nonlocal的作用應該是把i變成全域性變數,這樣每次修改都可以生效,跟global關鍵字有點像。既然找到乙個知識盲點,那就將它徹底解決吧。
nonlocal與global
說了這麼多,是時候回到主題了,nonlocal關鍵字到底是什麼?在什麼情況下用呢? 簡單來說,nonlocal關鍵字是用來改變變數的作用域的。
直接解釋不太好懂,先來看兩個例子吧。
def outside():
msg = "outside!"
def inside():
msg = "inside!"
print(msg)
inside()
print(msg)
執行結果是什麼呢?
inside!
outside!
結果應該很好理解, 在outside函式裡面定義了inside函式並且執行。當執行outside函式時,inside裡面的msg變數指向了"inside!",outside裡面的msg指向了"outside!", 也就是說這裡其實有兩個msg變數,並且指向了不同的值。如下圖所示:
再來看下面這個例子:
def outside():
msg = "outside!"
def inside():
nonlocal msg
msg = "inside!"
print(msg)
inside()
print(msg)
現在的執行結果就變成了:
inside!
inside!
兩段**之間的差別僅在於下面的例子多了一句 nonlocal msg。
這裡的nonlocal關鍵字起到了什麼作用呢?
nonlocal意思是告訴python,不要重新建立msg變數,而是使用outside中的msg變數來賦值。
畫個圖就很好懂了。
在這個例子中, msg變數只被建立了一次,首先將"outside!"賦值給msg,然後將"inside!"賦值給了msg, 此時的msg已經指向了"inside!"。因此執行的結果兩個都是"inside!"。
現在我們知道了,nonlocal是用來改變變數的作用域的。本例中,nonlocal將inside函式裡面的msg變數的作用域變成了outside塊中的區域。nonlocal跟global 這兩個關鍵字非常像,不同之處在於nonlocal用於外部函式作用域的變數,而global用於全域性範圍內的變數。 這就是nonlocal關鍵字的作用。但是還有一點值得注意,先看下面的例子。
def outside():
d =
def inside():
d["inside"] = 2
print(d)
inside()
print(d)
大家覺得輸出是什麼呢?
實際輸出是這樣的:
原因嘛,當然是因為dict是可變物件了,但由於 d["inside"] = 2 這樣的語句是有點讓人迷惑的,看起來很像重新賦值。實際上dict的賦值是呼叫了setitem方法。這樣看就不會感到迷惑了。
# 下面的**是等價的。
d["inside"] = 2
d.__setitem__("inside", 2)
關於nonlocal關鍵字,應該講清楚了吧。至於python的閉包,其實還是挺複雜的,上面的只是幾個例子,想要更加深入的學習可以上stackoverflow上看看大佬們的回答。很有學習的價值。
文源網路,僅供學習之用,侵刪。
閉包小案例
閉包可以用在許多地方。它的最大用處有兩個,乙個是可以讀取函式內部的變數,另乙個就是讓這些變數的值始終保持在記憶體中。閉包的應用涉及作用域 函式的引數傳遞 變數提公升等知識,當迴圈使用時,通過畫圖的方式可以更好的去理解。以下的這段 n 只有1級引用 function fun n,s var a fun...
python 閉包 python 閉包
閉包 因為python中函式也可以當作物件,所以如果出現當我們返回乙個函式,而該函式含有外部變數的時候就形成了閉包。閉包的特點 是個巢狀函式 可以獲得非區域性的變數 將函式當作物件返回 看乙個例子會更易理解 def make printer msg msg hi there def printer ...
Python高階特性之閉包與裝飾器例項詳解
閉包 1.函式引數 1 函式名存放的是函式的位址 2 函式名 存放的是函式內的 3 函式名只是函式 空間的引用,當函式名賦值給乙個物件的時候,就是引用傳遞 def func01 print func01 is show test func01 print func01 print test test...