python對閉包的官方說法:閉包表示乙個內部函式裡對外部作用域(但不是全域性作用域)的變數進行引用,就認為內部函式是閉包。閉包可以形象的理解為乙個封閉的包裹,這個包裹就是乙個函式,且這個函式有乙個特點,它將外部作用域中的變數也包裹進去了。
閉包意味著,如果呼叫乙個函式a,這個函式a返回乙個函式b,那麼稱這個返回的函式b為閉包。
def
func
(name)
:#func為外部函式a
deffunc1
(age)
:#func1為內部函式b,且內部函式將外部作用域中的變數name也包裹進去,形成閉包
print
('name:'
,name,
'age:'
,age)
#此處呼叫的name為外部作用域(func函式的作用域)中的變數
return func1 #返回乙個func1的函式物件,也就是乙個閉包,其中帶有變數name
my_age = func(
'bigboss'
)#用變數my_age來接收func返回的函式物件
my_age(19)
#相當於呼叫func1(19)
my_age = func(
'bigbigboss'
)my_age(
20)
在上述**中,當呼叫函式func(『bigboss』)時就產生乙個閉包func1(),並用my_age來接收,注意此時func函式的傳參name就是呼叫時func函式的實參。運算結果在該示例中,閉包func1()包裹了外部變數name,這表示當函式func()的生命週期結束後,變數name依然會存在,應為它被閉包引用了,所以不會被系統**,故才可以被閉包函式func1()和函式my_age()使用。
my_age接受這個閉包後就相當於給閉包取了個叫做
my_age
的名字,故my_age(age) == func1(age),注意此時func1函式的傳參age就是my_age函式的實參。
name: bigboss age: 19
name: bigbigboss age: 20
def
hello_counter
(num =0)
:#預設引數num的初始化為0
count = num #count作為相對於函式counter()的外部作用域中的引數
defcounter()
:#閉包
nonlocal count #告訴直譯器這個count變數是在外部定義的
count +=
1print
('次數:'
,count)
return counter #返回閉包
hello = hello_counter(
)#使用變數hello接收函式物件counter
hello(
)hello(
)#呼叫兩次函式hello()
在上述**中,外部函式將num賦值給count,作為計數使用。運算結果首先使用變數hello來接受函式hello_counter()返回的閉包counter(),故此時hello() == counter(),故每呼叫一次hello()就相當於呼叫一次counter(),而閉包counter()能夠讓外部變數count自增,因此可以達到計算函式呼叫次數的目的。
注:此處用到了python關鍵字nonlocal,該關鍵字的作用是告訴直譯器這個count變數實在函式counter()的外部定義了,有了這個關鍵字,python就會從外層函式尋找變數count。
次數: 1
次數: 2
在python語言中,可以使用裝飾器給不同的函式或類插入相同的功能,且不影響原有函式和類的功能,還能新增新的功能。python中使用@符號來實現裝飾器,在定義裝飾器裝飾函式或類時,使用「
@裝飾器名稱
」的形式將符號「@
」放在函式或類的定義行之前。要想使用裝飾器來裝飾乙個函式或類,必須先定義這個裝飾器。在python中,定義裝飾器的格式與定義普通函式的格式完全一致,只不過裝飾器函式的引數必須要有函式或類物件。
然後再裝飾器函式中重新定義乙個新的函式或類,並且再其中執行某些功能前後使用被裝飾的函式或類。
最後返回這個新定義的函式或類。
def
func1
(func)
:#func為被裝飾的函式物件,符合「裝飾器函式的引數必須要有函式物件或類物件」這一條件
deffunc2
(x,y)
:#func2()為再裝飾函式中重新定義的乙個函式,並返回了被裝飾的函式func
x +=
1 y +=
2return func(x,y)
return func2 #最後返回這個新定義的函式
@func1 #使用裝飾器func1來裝飾函式sum
defsum
(a,b)
:print
('結果為:'
, a + b)
sum(1,
2)
**解讀
裝飾器@func1其實可以看作func1(sum)(a,b),它將函式sum作為函式物件傳給了func1,然後func1返回乙個新定義的函式物件func2,故可以理解為func1(sum) == func2
。
sum的引數a和b傳給了func2的x和y,故又可以理解為func1(sum)(a,b) == func2(a,b) == func2(x,y)
,之後發生新定義的函式func2的呼叫。
又新定義的函式返回的是被裝飾函式func的呼叫,而此時的func就是實參sum函式,故此處發生了sum函式的呼叫,而呼叫的引數a和b**於變化後的x和y,故裝飾器使函式sum加入了一些新的功能(這些功能包裝在新定義的函式func2中)
。
綜上可總結出下列關係:@func1 == func1(sum)(a,b) == func2(a,b) == func2(x,y) == func(x,y)
。
運算結果
結果為: 6
參考文獻
非同步圖書 // python程式設計——從入門到精通 葉維忠編著 人民郵電出版社
python中閉包和裝飾器
前言 程式語言發展的過程中,我們為了提高 利用率,發明了函式式程式設計。函式將 封裝起來,我們需要用到此功能函式的時候,呼叫一下就可以了。但是使用的過程中,也遇到了一些問題,比如函式實現的功能不夠,或者跟我們要實現的功能有些差別。腫麼辦呢?開啟函式內部 重新寫?可以嗎?可以!但是這就違背了函式式程式...
python中閉包 python中的閉包
一 定義 如果在乙個內部函式裡,對在外部作用域 但不是在全域性作用域 的變數進行引用,那麼內部函式就被認為是閉包 closure 這個定義是相對直白的,閉包有三個條件 1.函式巢狀 2,內部函式呼叫外部函式的變數 3.返回內部函式 defa a defb b s a breturnsreturnb ...
python 閉包 Python中的閉包
一 什麼是閉包 在談之前,我們先來說說作用域,變數的作用域無非就兩種 全域性變數和區域性變數。函式內部可以直接讀取全域性變數,但是在函式外部無法讀取函式內部的區域性變數。出於種種原因,我們有時候需要獲取到函式內部的區域性變數。但是,正常情況下,這是辦不到的!只有通過變通的方法才能實現。於是就引入了閉...