Python高級--閉包與裝飾器
前言:在Python中,閉包是一種非常有用的功能!它通常與裝飾器一起搭配使用,可以在不改變被裝飾函數的功能的基礎上,完成更多的功能。如權限認證。
一、如何定義閉包
1.閉包就是兩個嵌套的函數,外層函數返回內層函數的引用,而且外層函數必須攜帶參數!爲什麼外層函數必須要有參數呢?可以思考一下!
基本格式如下:
1 def outer_fun(func):
2 def inner_fun():
3 pass
4 return inner_fun
2.與普通函數的區別:
閉包的外層函數的變量可以在內存中保存着,有點像類;而普通函數一旦執行完,那麼就要回收內存。
3.萬能閉包
def outer_func(func):
def inner_func(*args, **kwargs):
func(*args, **kwargs)
return inner_func
二、裝飾器
1.什麼是裝飾器:@閉包的外層函數名
2.裝飾器的作用:不修改被裝飾函數的功能外,再通過閉包的方式添加額外的功能!
3.基本結構:
1 def outer_func(func):
2 def inner_func():
3 pass
4 return inner_func
5
6
7 @outer_func # test = outer_func(test)
8 def test():
9 pass
重點:上述代碼的第七行和第八行是重點,看到這個語法糖要想到其本質: test = outer_func(test)
4.結論:
(1). 裝飾前的test函數和閉包外層函數的func是一樣的;
(2). 裝飾後的test函數是閉包內層函數的引用,也就是說此時test指向了inner_func函數體;
(3). 裝飾器一般不改變原先函數的行爲。
5.裝飾器的一個小問題
與其說是裝飾器的問題,不如說是閉包的問題!
一個函數被裝飾之後,它的函數名會發生變化,變成了閉包的內層函數名。那該怎麼解決這個問題呢?
使用funtools.wraps()這個裝飾器就可以完美解決這個問題了,因爲這個裝飾器會保留被裝飾函數的一些基本信息。
1 import functools
2
3
4 def outer_func(func):
5 # 使用這個裝飾器,可以保留被裝飾函數的一些基本信息,如名稱不變
6 @functools.wraps(func)
7 def inner_func(*args, **kwargs):
8 func(*args, **kwargs)
9
10 # inner_func.__name__ = func.__name__
11 return inner_func
12
13
14 @outer_func
15 def test(*args, **kwargs):
16 print('%s 正在運行。。。。' % test.__name__)
17
18
19 test()
三、裝飾器內存圖解
1.一個裝飾器裝飾一個函數的內存圖解:
2.兩個裝飾器裝飾一個函數的內存圖解
四、裝飾器傳參數
1.結構:由三層函數構成的,即用一個函數把閉包給封裝起來,這個函數必須帶有參數!
最外層函數(set_args)返回閉包的外層函數的引用;
閉包的外層函數(outer_fun)還是返回內層函數的引用。
1 def set_args(args):
2 def outer_fun(func):
3 def inner_fun(*args, **kwargs):
4 func(*args, **kwargs)
5 return inner_func
6 return outer_fun
2.運行流程:
1 @set_args('123')
2 def test():
3 print('test')
4
5 test()
(1).先執行@右邊的函數,即先執行set_args('123'),
(2).執行完set_args()後返回outer_fun的引用,此時就是test = outer_fun(test)這個熟悉的語法了,
(3).接下來就執行被裝飾的函數了。