python的閉包與裝飾器
閉包指內部函式對外部函式作用域裡變數的引用
內部函式與外部函式:
def func():#外部函式 print("this is func") def func1(num):#內部函式 print("this is func1")
由於內部函式的宣告是在外部函式的作用域內,所以我們在外面是無法呼叫內部函式的,如何呼叫?在func()中return func1
def func():#外部函式 a=1 print("this is func") def func1(): print("this is func1")return func1 var=func() var()
函式的閉包:
def func():#外部函式 a=1 print("this is func") def func1(num): print("this is func1") print(num+a) return func1 var=func() var(3)
讓內部函式可以使用外部函式的變數,也就是說呼叫func()時除了func1() return出來了,外部函式中用到的變數也存活下來了
閉包內的閉包函式(func1())私有化了變數,完成了資料的封裝,類似於面向物件
mylist=[1,2,3,4,5] def func(obj): print("func:",obj) def func1(): obj[0]+=1 print("func1:",obj) return func1 var=func(mylist) var() var() var()
del var才宣佈閉包生命週期的結束,由於閉包包裝了一些資料,所以當大規模使用的時候是對記憶體不利的
實現裝飾器的時候會利用到閉包,裝飾器,語法糖@
裝飾器:
@func1 def func(): print("aaa")
在我們執行func()時,會首先執行func1()中的內容
如果我們去掉裝飾器@func1,那麼func就只會執行print,加上裝飾器的話就會新增某些功能。因此裝飾器的意義就是不影響原有函式的功能,新增新的功能
一般用於拿到了別人的第三方api,覺得功能簡陋還需要新增功能時,就可以使用裝飾器
def func1(func): def func2(): print("112233") return func() return func2 @func1 def myPrint(): print("hello, this is my print") myPrint()
相當於給myPrint函式做了裝飾,我們呼叫的myPrint()=func2()+func(),這裡的func是傳進來的引數,也就是myPrint本身
相當於func1(myPrint)()
整個呼叫流程:
func1將被修飾函式myPrint作為引數接收上來
func1接收到了myPrint後返回內部的func2
func2返回回來之後,將返回回來的結果繼續加上括號
https://www.cnblogs.com/wangtianning1223/p/14118933.html中的程式其實相當於
funA(funB(funC))()
因此funA,funB的執行順序是相反的,而warp的順序是正序
帶引數的裝飾器,多一層包裝接收裝飾器引數
def arg_func(sex): def func1(a): def func(): if sex=="man": print("you are man") if sex=="woman": print("you are woman") return a() return func return func1 @arg_func(sex="man") def man(): print("work for money") @arg_func(sex="woman") def woman(): print("work for money") man() woman()
相當於arg_func(sex)(func)()==>func1()==>func2()==>print("you are man")+man() || print("you are woman")+woman()
被裝飾的函式帶引數,只需在最內部函式傳入引數即可
def func1(func): def func2(x,y): print(x,y) x+=5 y+=5 return func(x,y) return func2 @func1 def mysum(a,b):#a=a+5,b=b+5使用裝飾器修改 print(a+b) mysum(1,2)
注意return func()的時候要把引數xy也返回
無情的摸魚機器