在 python 中,函式也是乙個物件。因此,我們在定義函式時,可以再巢狀定義乙個函式,並將該巢狀函式返回,比如:
上面的**中,函式from math import pow
def make_pow(n):
def inner_func(x): # 巢狀定義了 inner_func
return pow(x, n) # 注意這裡引用了外部函式的 n
return inner_func # 返回 inner_func
make_pow
裡面又定義了乙個內部函式inner_func
,然後將該函式返回。因此,我們可以使用make_pow
來生成另乙個函式:
我們還注意到,內部函式>>> pow2 = make_pow(2) # pow2 是乙個函式,引數 2 是乙個自由變數
>>> pow2
>>> pow2(6)
36.0
inner_func
引用了外部函式make_pow
的自由變數n
,這也就意味著,當函式make_pow
的生命週期結束之後,n
這個變數依然會儲存在inner_func
中,它被inner_func
所引用。
像上面這種情況,乙個函式返回了乙個內部函式,該內部函式引用了外部函式的相關引數和變數,我們把該返回的內部函式稱為閉包(closure)。>>> del make_pow # 刪除 make_pow
>>> pow3 = make_pow(3)
traceback (most recent call last):
file "", line 1, in nameerror: name 'make_pow' is not defined
>>> pow2(9) # pow2 仍可正常呼叫,自由變數 2 仍儲存在 pow2 中
81.0
在上面的例子中,inner_func
就是乙個閉包,它引用了自由變數n
。
這裡構造乙個類,用於求乙個點到另乙個點的距離:>>> pow_a = make_pow(2)
>>> pow_b = make_pow(2)
>>> pow_a == pow_b
false
用閉包來實現:from math import sqrt
class point(object):
def __init__(self, x, y):
self.x, self.y = x, y
def get_distance(self, u, v):
distance = sqrt((self.x - u) ** 2 + (self.y - v) ** 2)
return distance
>>> pt = point(7, 2) # 建立乙個點
>>> pt.get_distance(10, 6) # 求到另乙個點的距離
5.0
可以看到,結果是一樣的,但使用閉包實現比使用類更加簡潔。def point(x, y):
def get_distance(u, v):
return sqrt((x - u) ** 2 + (y - v) ** 2)
return get_distance
>>> pt = point(7, 2)
>>> pt(10, 6)
5.0
閉包的概念很簡單,但實現起來卻容易出現一些誤區,比如下面的例子:
在該例子中,我們在每次def count():
funcs =
for i in [1, 2, 3]:
def f():
return i
return funcs
for
迴圈中建立了乙個函式,並將它存到funcs
中。現在,呼叫上面的函式,你可能認為返回結果是 1, 2, 3,事實上卻不是:
為什麼呢?原因在於上面的函式>>> f1, f2, f3 = count()
>>> f1()
3>>> f2()
3>>> f3()
3
f
引用了變數i
,但函式f
並非立刻執行,當for
迴圈結束時,此時變數i
的值是3,funcs
裡面的函式引用的變數都是 3,最終結果也就全為 3。
因此,我們應盡量避免在閉包中引用迴圈變數,或者後續會發生變化的變數。
那上面這種情況應該怎麼解決呢?我們可以再建立乙個函式,並將迴圈變數的值傳給該函式,如下:
def count():
funcs =
for i in [1, 2, 3]:
def g(param):
f = lambda : param # 這裡建立了乙個匿名函式
return f
return funcs
>>> f1, f2, f3 = count()
>>> f1()
1>>> f2()
2>>> f3()
3
攜帶狀態的LiveData
在android mvvm架構中,livedata作為通知ui更新的橋梁,地位極其重要,可以說是mvvm的核心元件。class uservm viewmodel 複製 這樣的 會大量出現在我們的vm層中。然而非同步操作不是立即的,而且有進度,有狀態的。我們的ui很可能需要知道當前的非同步資料操作是否...
python 閉包 python 閉包
閉包 因為python中函式也可以當作物件,所以如果出現當我們返回乙個函式,而該函式含有外部變數的時候就形成了閉包。閉包的特點 是個巢狀函式 可以獲得非區域性的變數 將函式當作物件返回 看乙個例子會更易理解 def make printer msg msg hi there def printer ...
python怎麼閉包 python的閉包
一 思考乙個問題 我們要給定乙個x,要求一條直線上x對應的y的值。公式是y kx b。我們需要用k,b來確定這條直線,則我們實現的函式應該有3個引數 defline k,b,x print k x b line 1,3,4 line 1,3,5 line 1,3,6 可以看到,我們每次修改x都要重新...