我們通過兩個例項來解開我們的疑惑:
例項一:
def實際輸出結果為:war1(func):
def inner(*args, **kwargs):
print("
*****=war1 start*****")
func(*args, **kwargs)
print("
*****=war1 end*****")
return
inner
defwar2(func):
def inner(*args,**kwargs):
print("
*****=war2 start*****")
func(*args,**kwargs)
print("
*****=war2 end*****")
return
inner
@war1
@war2
deff():
print("
****self****")
f()
*****=war1 start*****好吧這個結果似乎有點出乎我們的意料:不是說好的誰近誰先來的嘛(我褲子都脫了,結果。。。)*****=war2 start*****
****self****
*****=war2 end*****
*****=war1 end*****
我們自己臆想的結果:
*****=war2 start*****那麼首先我們知道我們為乙個函式裝飾其實就相當於:*****=war2 end*****
*****=war1 start*****
*****=war1 end*****
****self****
f =war1(f)或者那麼問題來了:f = war2(f) ####這個時候f=inner,而不再是原來的函式。只是使用者不知道而已。
當走到這一步的時候說明,兩個inner函式已經執行了。
也就是他們發生在我們真正的呼叫之前,那麼真正呼叫的時候才是我們按照我們的就近原則,也就是限制性war2中的**,在執行war1中的**。
例項二:
def實際執行結果為:decorator_a(func):
print ('
get in decorator_a')
def inner_a(*args, **kwargs):
print ('
get in inner_a')
return func(*args, **kwargs)
return
inner_a
defdecorator_b(func):
print( '
get in decorator_b')
def inner_b(*args, **kwargs):
print ('
get in inner_b')
return func(*args, **kwargs)
return
inner_b
@decorator_b
@decorator_a
deff(x):
print( '
get in f')
return x * 2f(1)
執行結果為什麼是先執行get
indecorator_a
get
indecorator_b
get
ininner_b
get
ininner_a
get
in f
inner_b
再執行inner_a
呢?為了徹底看清上面的問題,得先分清兩個概念:函式和函式呼叫。上面的例子中f
稱之為函式,f(1)
稱之為函式呼叫,後者是對前者傳入引數進行求值的結果。在python中函式也是乙個物件,所以f
是指代乙個函式物件,它的值是函式本身,f(1)
是對函式的呼叫,它的值是呼叫的結果,這裡的定義下f(1)
的值2。同樣地,拿上面的decorator_a
函式來說,它返回的是個函式物件inner_a
,這個函式物件是它內部定義的。在inner_a
裡呼叫了函式func
,將func
的呼叫結果作為值返回。
其次得理清的乙個問題是,當裝飾器裝飾乙個函式時,究竟發生了什麼。現在簡化我們的例子,假設是下面這樣的:
def正如很多介紹裝飾器的文章裡所說:decorator_a(func):
print ('
get in decorator_a
')def inner_a(*args, **kwargs):
print ('
get in inner_a
')return func(*args, **kwargs)
return
inner_a
@decorator_a
deff(x):
print ('
get in f
')return x * 2
@decorator_a所以,當直譯器執行這段**時,deff(x):
print (get in f
')return x * 2
#相當於
deff(x):
print ('
get in f
')return x * 2f = decorator_a(f)
decorator_a
已經呼叫了,它以函式f
作為引數, 返回它內部生成的乙個函式,所以此後f
指代的是decorater_a
裡面返回的inner_a
。所以當以後呼叫f
時,實際上相當於呼叫inner_a
,傳給f
的引數會傳給inner_a
, 在呼叫inner_a
時會把接收到的引數傳給inner_a
裡的func
即f
,最後返回的是f
呼叫的值,所以在最外面看起來就像直接再呼叫f
一樣。
那麼對於例項一與例項二,還有一點不同的,哈哈哈,那就是被裝飾函式的執行順序,在兩個例項中是不一樣的,這是為什麼呢?
這個就跟我們的裝飾器沒什麼關係了:
主要是因為inner函式的輸出與函式的執行的乙個先後順序。
帶函式的裝飾器 多個裝飾器裝飾乙個函式
一 帶引數的裝飾器 開關 author administrator f true defouter f def wap fun ggdef inner args,kwargs iff print inner before ret fun args,kwargs gg print inner afte...
乙個裝飾器裝飾乙個函式
2 如果鍵不存在,則新增到字典中。請使用裝飾器來實現,順便複習下 args和 kwargs的用法 a defselect func def inner args,kwargs if len args 0 if kwargs key in kwargs data print 鍵存在 else func...
裝飾器如何裝飾乙個函式
裝飾器如何裝飾乙個函式?今天番茄加速就來講一下。printstar函式接收乙個函式f,返回值也是乙個函式,所以滿足裝飾器的結構要求,所以printstar是乙個裝飾器。def printstar f def g print 20 f print 20 return g printstar裝飾器實現f...