關於多個裝飾器裝飾乙個函式執行順序的問題

2022-02-03 11:43:45 字數 3765 閱讀 5216

我們通過兩個例項來解開我們的疑惑:

例項一:

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裡的funcf,最後返回的是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...