寫代碼的時候有一個原則,開放封閉原則(面向對象):對某些東西開放,對某些封閉,在裝飾器這里,函數內部是封閉的,不允許改變函數的內部。
裝飾器用來裝飾函數,可以讓函數在執行之前或者執行之后,做一些操作,讓函數調用者的操作不變,就能在執行前后做一些操作。簡單來說,裝飾器感覺就類似于裝修,提供一些額外的功能。
裝飾器的本質就是將原函數封裝到另一個函數里面。
裝飾器原理剖析
關鍵點1
def f1():print('1') def f1():print('2') f1()
上面這段函數執行后,輸出的結果為2,因為python解釋器從上往下執行,先把第一個f1放進內存,碰到第二個f1函數后又把它放進內存,所以f1指的是第二個函數的內容。
關鍵點2
@符號:
@符號具有特殊性,@函數名,碰到后,先執行函數,并且將其下面的函數名當作參數,如:
def outer(func):pass @outer def f1():pass def f2():pass
碰到@outer之后,先執行outer函數,然后將f1作為參數,此時func=f1(原來的f1函數)
outer的返回值賦值給f1,此時f1=outer返回值,所以以后再執行f1,就執行新的f1函數
?關鍵點3
只要函數用了裝飾器,函數就會重新定義為裝飾器的內層函數,所以如果函數有參數的話,裝飾器的內層函數也要有相應的參數來接收,即inner函數要有相應的參數,同時,func函數等于原來的函數,所以func函數也要有相應的參數
inner(*args,**kwargs)
ret? = func(*args,**kwargs)
以后寫裝飾器就按照上面的寫法來,這樣就不用擔心參數的問題了,碉堡了。
裝飾器例子:
#!/usr/bin/env python # -*- coding:utf-8 -*-def outer(func):def inner(*args,**kwargs):print('你')ret = func(*args,**kwargs)print('好')return retreturn inner@outer def f1(a1):print('aa')return a1@outer def f2(s1,s2):print('bb')return s1,s2ret1 = f1(1)ret2 = f2(2,3)print(ret1,ret2)
上面的程序輸出結果為:
你
aa
好
你
bb
好
1 (2, 3)
可以看到,在不改變函數的基礎上,函數執行了一些別的操作。上面這是一個裝飾器裝飾一個或多個函數的場景
多個裝飾器裝飾一個函數
#!/usr/bin/env python # -*- coding:utf-8 -*-def outer0(func):def inner(*args,**kwargs):print('before')ret = func(*args,**kwargs)print('after')return retreturn inner def outer(func):def inner(*args,**kwargs):print('你')ret = func(*args,**kwargs)print('好')return retreturn inner @outer0 @outer def f1():print('self')return None f1()
輸出結果為:
before
你
self
好
after
可以這樣理解:
#part1
#一個新的函數,不妨叫這個函數為index
@outer def f1():print('self')return None
然后代碼就變成了下面這樣:
#part2
@outer0 def index():pass
最后函數的執行順序是這樣的:先執行最外層的part2,即先輸出before,在執行index函數,最后輸出after,執行index函數的時候,就是執行part1,先輸出'你',在輸出'self',再輸出'好'。