Python中的返回函式與閉包

2022-03-11 17:17:30 字數 4163 閱讀 8630

返回函式,顧名思義,就是高階函式可以把函式作為return值返回。與閉包的關係是:閉包需要以返回函式的形式實現。

一. 返回函式

比如我們有乙個求和函式:

>>> def

calc_sum(num_list):

s =0

for i in

num_list:

s +=i

return

s>>> calc_sum([1,2,3,4])

10

當我們不需要立刻求和,而是後面根據需要再計算結果時,我們可以返回求和的函式,而不是直接返回計算結果。這就是返回函式。

>>> def

lazy_calc_sum(num_list):

defcalc_sum():

s =0

for i in

num_list:

s +=i

return

s

return

calc_sum

>>> f_lazy = lazy_calc_sum([1,2,3,4])

>>>f_lazy

.calc_sum at 0x0000003a8d92e9d8>

>>>f_lazy()

10

很顯然,這樣能讓我們根據需求,節省計算資源。

二. 閉包

在上面的例子中,我們在函式lazy_clac_sum中又定義了函式calc_sum,並且,內部函式calc_sum可以引用外部函式lazy_calc_sum的引數和區域性變數,當lazy_calc_sum返回函式calc_sum時,相關引數和變數都儲存在返回的函式中,這種稱為「閉包(closure)」。

如果讓定義更加清晰一些: 如果在乙個內部函式裡對在外部作用域(但不是在全域性作用域)的變數進行引用,但不在全域性作用域裡,則這個內部函式就是乙個閉包。

實際上,閉包的用處/優點有兩條:

>>> def

download_enter(download_times):

defdownload():

nonlocal download_times

download_times += 1

print("

this is the %s time download

" %download_times)

return

download

>>>

>>> d =download_enter(0)

>>>d()

this

is the 1time download

>>>d()

this

is the 2time download

>>>d()

this

is the 3 time download

下面的例子是閉包根據外部作用域的區域性變數來得到不同的結果,這有點像一種類似配置功能的作用,我們可以修改外部的變數,閉包根據這個變數展現出不同的功能。比如有時我們需要對某些檔案的特殊行進行分析,先要提取出這些特殊行。

def

make_filter(keep):

defthe_filter(file_name):

file =open(file_name)

lines =file.readlines()

file.close()

filter_doc = [i for i in lines if keep in

i]

return

filter_doc

return the_filter

如果我們需要取得檔案"result.txt"中含有"pass"關鍵字的行,則可以這樣使用例子程式

filter = make_filter("

pass

")

filter_result = filter("

result.txt

")

以上兩種使用場景,用物件導向也是可以很簡單的實現的,但是在用python進行函式式程式設計時,閉包對資料的持久化以及按配置產生不同的功能,是很有幫助的。

關於閉包的2個常見錯誤:

1. 嘗試在閉包中改變外部作用域的區域性變數

def

foo():

a = 1

defbar():

a = a + 1

return

a

return bar

>>> c = foo()  

>>> print c()

traceback (most recent call last):

file "", line 1, in file "", line 4, in bar

unboundlocalerror: local variable 'a' referenced before assignment

這段程式的本意是要通過在每次呼叫閉包函式時都對變數a進行遞增的操作。但在實際使用時,a = a + 1的a會被python直譯器認為是bar()函式的區域性變數,從而引起「referenced before assignment」的錯誤。

解決方法有兩個:

下面是例子:

>>> def

foo():

a = 1b = [1]

defbar():

nonlocal a

a = a + 1b[0] = b[0] + 1

return

a,b[0]

return

bar>>> c =foo()

>>> print

(c())

(2, 2)

>>> print

(c())

(3, 3)

>>> print

(c())

(4, 4)

2. 誤以為返回的函式就已執行,對執行結果誤判

直接舉例子說明:

def

count():

fs =

for i in range(1, 4):

deff():

return i*i

return

fsf1, f2, f3 = count()

在上面的例子中,每次迴圈,都建立了乙個新的函式,然後,把建立的3個函式都返回了。

你可能認為呼叫f1()f2()f3()結果應該是149,但實際結果是:

>>>f1()

9>>>f2()

9>>>f3()

9

全部都是9!原因就在於返回的函式引用了變數i,但它並非立刻執行。等到3個函式都返回時,它們所引用的變數i已經變成了3,因此最終結果為9

返回閉包時牢記一點:返回函式不要引用任何迴圈變數,或者後續會發生變化的變數。

如果一定要引用迴圈變數怎麼辦?方法是再建立乙個函式,用該函式的引數繫結迴圈變數當前的值,無論該迴圈變數後續如何更改,已繫結到函式引數的值不變:

def

count():

deff(j):

defg():

return j*j

return

g fs =

for i in range(1, 4):

#f(i)立刻被執行,因此i的當前值被傳入f()

return fs

結果是:

>>> f1, f2, f3 =count()

>>>f1()

1>>>f2()

4>>>f3()

9

python返回函式閉包

注意到返回的函式在其定義內部引用了區域性變數args,所以,當乙個函式返回了乙個函式後,其內部的區域性變數還被新函式引用,所以,閉包用起來簡單,實現起來可不容易。另乙個需要注意的問題是,返回的函式並沒有立刻執行,而是直到呼叫了f 才執行。我們來看乙個例子 def count fs for i in ...

Python 返回函式 閉包小結

即函式的返回值可以為乙個函式 乙個例子 def outer 外函式 t 0 def inner 內函式 t 0 1return t 0 return inner 外函式返回內函式的引用 實現機制 外函式中定義了內函式,內函式運用了外函式的臨時變數 外函式繫結給內函式的區域性變數 閉包變數 外函式返回...

python返回函式 python中返回函式

python的函式不但可以返回int str list dict等資料型別,還可以返回函式!例如,定義乙個函式 f 我們讓它返回乙個函式 g,可以這樣寫 deff print call f 定義函式g defg print call g 返回函式g return g 仔細觀察上面的函式定義,我們在函...