閉包Closure
阿新 • • 發佈:2018-12-10
恩~ 如期來啦“閉包”~
一、函式作為返回值
介紹“閉包”之前,先了解一下函式作為返回值的情況。高階函式除了可以接收函式作為引數外,還可以把函式作為結果值返回。例如之前介紹的裝飾器中,就出現了將函式作為返回值。
二、閉包
1、產生閉包的條件以及作用
什麼是閉包?當在函式中巢狀另一個函式時,如果內部函式引用了外部函式的變數,則可能產生閉包。所以閉包產生的三個條件(缺一不可):
- 1、必須巢狀一個內部函式
- 2、內部函式必須引用外部函式的變數
- 3、外部函式必須返回內部函式
那為什麼要試用閉包,閉包的作用呢?
- 1、閉包可以根據外部函式的區域性變數來得到不同的結果
- 2、當閉包執行完成後,仍可以保持當前的執行環境,執行結果依賴於該函式上一次的執行結果
2、閉包舉例
栗子一:求序列之和
>>> def calc_sum(*args):
... ax = 0
... for n in args:
... ax = ax + n
... return ax # 返回變數
...
>>> calc_sum(1,2,3)
6
但是,現在如果要求不需要立即取得求和結果,而是在後面的程式碼中,根據需要再計算,該怎麼弄呢?我們可以不返回求和的結果,而返回求和的函式,如下:
>>>def lazy_sum(*args): ... def sum(): # sum()是內部函式,可以利用外部函式的引數 ... ax = 0 ... for n in args: # sum()中使用外部函式的區域性變數 ... ax = ax + n ... return ax ... return sum # 形成閉包,此時,*args儲存在返回的函式中 ... >>>f = lazy_sum(1,3,5,7,9) >>>f # 此時返回的是求和函式 >>> f() # 呼叫函式f()時,才真正計算求和的結果 25
注意:
-
lazy_sum()
函式的內部執行順序,執行f時,執行到return sum
處,*args
儲存在返回函式中,返回的是sum()
函式。當執行f()
時,相當於執行sum()
,且包含*args
。 - 當我們呼叫
lazy_sun()
時,每次都會返回一個新的函式,即使傳入相同的引數,但是f()呼叫結果不影響。
我們來驗證第二點:
# 但是呼叫 f1() 與f2()的呼叫結果互不影響 >>> f1 = lazy_sum(1,3,5,7,9) >>> f2 = lazy_sum(1,3,5,7,9) >>> f1 <function lazy_sum.<locals>.sum at 0x013DD618> >>> f2 <function lazy_sum.<locals>.sum at 0x02F92DF8> >>> f1 == f2 False >>> f1() == f2() True >>> f1() 25 >>> f2() 25 >>> id(f1()) 1627215984 >>> id(f2()) 1627215984
說明:f1
與f2
返回函式的位置不一樣,所以f1==f2
返回結果為False
。但是不影響最後的執行結果,f1()
與f2()
的執行結果均為25,且用id()
進行檢視,指向是同一塊區域。
栗子二:
def count():
fs = []
for i in range(1, 4):
def f(): # 返回函式f()放在迴圈裡
return i*i
fs.append(f)
return fs
f1, f2, f3 = count()
實際執行結果為:f1=9 f2=9 f3=9
可能與實際想的([1,4,9])有點不一樣。因為f()
函式放在了for
迴圈裡,只有當迴圈結束後,最後才返回i=3的執行結果9。所以返回函式最好不要引用任何迴圈變數,或者說後續可能變化的量。那如何來修改呢?
def count():
def f(j):
def g():
return j*j # 形成閉包
return g
fs = []
for i in range(1, 4):
fs.append(f(i)) # 一個i值進入後,f(i)立刻被執行,並加入到fs中
return fs
f1, f2, f3 = count() # 返回函式g沒有引用j
最後結果:[1,4,9] 即f1=1 f2=4 f3=9
三、匿名函式lambda
-
定義:匿名函式指一類無需定義識別符號函式名的函式或者子程式。Python允許使用
lambda
關鍵字創造匿名函式。 -
語法:
lambda 引數:表示式
或者lambda 形參1,…,形參n : function(形參),入參1,…,入參n
-
注意:1、
lambda
函式可以接收任意多個引數並且返回單個表示式的值; 2、lambda中不能包含命令,返回的表示式不能超過一個。 - 優點:1、可以省去定義函式的過程,精簡程式碼; 2、對於一些抽象的、不會重複使用的函式可以用lambda進行定義。
例子:
>>> list( map( lambda x: x*x ,[1,2,3] ) )
[1, 4, 9]
其中lamdba x : x*x
實現的是:def f(x): return x*x
的功能。
- 可以把匿名函式賦值給一個變數,再利用變數呼叫該函式。例如:
>>> f = lambda x:x*x
>>> f(5) # 呼叫
>>> g = lambda x,y=2 : x*y
>>> g(2,4)
8
>>> g(2) # 預設y=2
4
- 可以把匿名函式作為返回值返回,例如:
return lambda x:x*x
❤ thanks for watching, keep on updating...