關於閉包以及其常見問題的理解 基於python

2021-08-25 06:06:40 字數 2795 閱讀 1889

在 python 中,返回值為乙個函式名的函式被稱為高階函式

而所謂返回乙個函式,一般情況下即意味著:執行這個函式並輸出相應結果:

# 定義乙個返回值為函式的函式

defmyf1

():def

myf2

(): print("in myf2")

return

2return myf2

# 使用上面定義

# 呼叫myf1, 返回乙個函式myf2,賦值給f2

f2 = myf1()

f2()

上述**的執行結果為:

in myf2

2

其實質是:呼叫了 myf1, 返回乙個函式 myf2,賦值給了 f2,則 f2 的執行結果即為 myf2() 函式的執行結果

上述例子中,作為返回值的函式並沒有和其所處於的外部函式有過多的關聯。

當作為返回值的函式使用了其所處的外部函式的引數及區域性變數時,即出現了閉包:

# args:引數列表

# 1 myf4定義函式,返回內部定義的函式myf5

# 2. myf5使用了外部變數,這個變數是myf4的引數

defmyf4

( *args):

defmyf5

(): rst = 0

for n in args:

rst += n

return rst

return myf5

f5 = myf4(1,2,3,4,5,6,7,8,9,0)

f5()

呼叫 f5,結果為:

45
定義:

乙個函式在其內部定義函式,並且內部的函式使用了外部函式的引數或者區域性變數,當內部函式被作為返回值的時候,相關的引數和變數將儲存在作為返回值的函式中,這種結構,叫做閉包。

閉包結構有以下特性:

返回的函式並不會立刻執行,它會保留所使用的相關的引數和變數,在呼叫的時候才會被執行

所謂 「相關的引數和變數將儲存在作為返回值的函式中」 ,其實際是傳址操作而非傳值,即儲存在函式裡的引數的值並不是不會改變的

這些特性會在典型的閉包會遇到的坑中體現:

來看案例:

def

count

():# 定義列表,列表裡存放的是定義的函式

fs =

for i in range(1,4):

# 定義了乙個函式f

# f是乙個閉包結構

deff

():return i*i

return fs

f1,f2,f3 = count()

print(f1())

print(f2())

print(f3())

上述例子中,我們定義了乙個 count 函式,其中的 for 迴圈將執行三次,每次呼叫都會將乙個 f(i) 函式放入 fs 這個列表中作為新的一項。

因為 fs 是乙個以函式作為元素的列表, 所以這裡構成閉包的還是最外層返回 fs 的 count 函式。

接下來的賦值語句。使用了可迭代資料的特性,將 count() 函式呼叫後得到的列表分拆為三個元素,分別賦值給 f1 , f2 , f3 。則此三個變數實際為函式變數

按照一般的理解,三次迴圈時的 i 值分別為 1,2,3 。則上述**的執行結果應該為 1 4 9

但實際上…… 都說了有坑那肯定不是以為的那樣。

實際結果:

原因在於上述的第二點特性。

作為返回值的函式 (fs 列表中的元素)使用了迴圈變數 i,因為返回的函式不會立即執行,因此,當三個函式都被返回時,i 的值已經變成了 3,因此在呼叫的時候,i 已經是 3。

此問題描述為:

返回閉包時,返回函式不能引用任何迴圈變數

注意哦,這裡的 「f1,f2,f3 = count()」 與該特性無關,只是乙個普通的賦值而已。

關於儲存在各個返回函式中的引數 i 的值的變化過程可參考下圖:

(自己拿 ppt 畫的,湊合看,誰沒有個第一次。。)

可以看到,每一次迴圈之後,可以看做是生成了乙個偏函式(即引數固定的函式),而這個引數 i 的值一直在變化,到了執行的時候,就已經是 3 了。

其解決辦法是,再建立乙個函式,用該函式的引數繫結迴圈變數當前的值,無論該迴圈變數後續如何更改,已繫結到函式引數的值不變,即 將傳址變成傳值,切斷函式與會變化的迴圈引數 i 的關聯。

# 修改上述函式

defcount2

():# 在外面再套一層

deff

(j):

defg

():return j*j

return g

fs =

for i in range(1,4):

return fs

f1,f2,f3 = count2()

print(f1())

print(f2())

print(f3())

其執行結果:

1

49

前端常見問題之 閉包篇

閉包實際上在寫 的時候用到過很多遍,但是想要真正把它解釋清楚卻不容易。當然,這也是前端核心之一。開始吧 一 變數的作用域 變數的作用域無非兩種 全域性作用域和塊級作用域 也就是在 中的變數 全域性作用域 全域性作用域可以被所有的函式所訪問,即函式內部可以直接讀取全域性變數 塊級作用域 變數只在 範圍...

關於閉包的理解

發表一下關於閉包的理解 首先把每乙個函式看成乙個乙個的 小黑屋 小黑屋裡面可以看到外面的東西,但外面卻看不到小黑屋裡面的東西,就好比是函式可以訪問外面全域性變數,但是外面卻訪問不了 小黑屋 裡面的變數 變數分為全域性變數和區域性變數 列 函式可以訪問外面全域性變數 var a 1 function ...

關於閉包的理解

js複習決定把閉包這個特性好好研究清楚 閉包是一種函式特性把,函式包含子函式,通過子函式訪問自身變數,然後在講子函式返回,達到普通函式做不到的特性 普通函式可以訪問全域性變數,但是不能訪問其他函式的變數 var n 1 function f1 f1 1 function f2 f2 b is not...