返回函式,顧名思義,就是高階函式可以把函式作為return值返回。與閉包的關係是:閉包需要以返回函式的形式實現。
一. 返回函式
比如我們有乙個求和函式:
>>> defcalc_sum(num_list):
s =0
for i in
num_list:
s +=i
return
s>>> calc_sum([1,2,3,4])
10
當我們不需要立刻求和,而是後面根據需要再計算結果時,我們可以返回求和的函式,而不是直接返回計算結果。這就是返回函式。
>>> deflazy_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)」。
如果讓定義更加清晰一些: 如果在乙個內部函式裡對在外部作用域(但不是在全域性作用域)的變數進行引用,但不在全域性作用域裡,則這個內部函式就是乙個閉包。
實際上,閉包的用處/優點有兩條:
>>> defdownload_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
下面的例子是閉包根據外部作用域的區域性變數來得到不同的結果,這有點像一種類似配置功能的作用,我們可以修改外部的變數,閉包根據這個變數展現出不同的功能。比如有時我們需要對某些檔案的特殊行進行分析,先要提取出這些特殊行。
defmake_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. 嘗試在閉包中改變外部作用域的區域性變數
deffoo():
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」的錯誤。
解決方法有兩個:
下面是例子:
>>> deffoo():
a = 1b = [1]
defbar():
nonlocal a
a = a + 1b[0] = b[0] + 1
return
a,b[0]
return
bar>>> c =foo()
(c())
(2, 2)
(c())
(3, 3)
(c())
(4, 4)
2. 誤以為返回的函式就已執行,對執行結果誤判
直接舉例子說明:
defcount():
fs =
for i in range(1, 4):
deff():
return i*i
return
fsf1, f2, f3 = count()
在上面的例子中,每次迴圈,都建立了乙個新的函式,然後,把建立的3個函式都返回了。
你可能認為呼叫f1()
,f2()
和f3()
結果應該是1
,4
,9
,但實際結果是:
>>>f1()9>>>f2()
9>>>f3()
9
全部都是9
!原因就在於返回的函式引用了變數i
,但它並非立刻執行。等到3個函式都返回時,它們所引用的變數i
已經變成了3
,因此最終結果為9
。
返回閉包時牢記一點:返回函式不要引用任何迴圈變數,或者後續會發生變化的變數。
如果一定要引用迴圈變數怎麼辦?方法是再建立乙個函式,用該函式的引數繫結迴圈變數當前的值,無論該迴圈變數後續如何更改,已繫結到函式引數的值不變:
defcount():
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 仔細觀察上面的函式定義,我們在函...