Python 攜帶狀態的閉包

2021-09-17 21:52:43 字數 2862 閱讀 6114

在 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所引用。

>>> 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

像上面這種情況,乙個函式返回了乙個內部函式,該內部函式引用了外部函式的相關引數和變數,我們把該返回的內部函式稱為閉包(closure)

在上面的例子中,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都要重新...