今天整理裝飾器,內嵌的裝飾器、讓裝飾器帶引數等多種形式,非常複雜,讓人頭疼不已。但是突然間發現了裝飾器的奧秘,原來如此簡單。。。。
第一步 :從最簡單的例子開始
# -*- coding:gbk -*-
'''示例1: 使用語法糖@來裝飾函式,相當於"myfunc = deco(myfunc)"
但發現新函式只在第一次被呼叫,且原函式多呼叫了一次'''
def deco(func):
print("before myfunc() called.")
func()
pr程式設計客棧int(" after myfunc() calledwww.cppcns.com.")
return func
@deco
def myfunc():
print(" myfunc() called.")
myfunc()
myfunc()
這是乙個最簡單的裝飾器的例子,但是這裡有乙個問題,就是當我們兩次呼叫myfunc()的時候,發現裝飾器函式只被呼叫了一次。為什麼會這樣呢?要解釋這個就要給出破解裝飾器的關鍵鑰匙了。
這裡@deco這一句,和myfunc = deco(my程式設計客棧func)其實是完全等價的,只不過是換了一種寫法而已
一定要記住上面這句!!!!
好了,從現在開始,只需要做替換操作就可以了。
將@deco 替換為myfunc = deco(myfunc)
程式首先呼叫deco(myfunc),得到的返回結果賦值給了myfunc (注意:在python中函式名只是個指向函式首位址的函式指標而已)
而deco(myfunc)的返回值就是函式myfunc()的位址
這樣其實myfunc 沒有變化,也就是說,最後的兩次myfunc()函式呼叫,其實都沒有執行到deco()。
有同學就問了,明明列印了deco()函式裡面的內容啊,怎麼說沒有呼叫到呢。這位同學一看就是沒有注意聽講,那一次列印是在@deco 這一句被執行的。大家親自動程式設計客棧手試一下就會發現" myfunc() called." 這句列印輸出了三次。多的那次就是@deco這裡輸出的,因為@deco 等價於myfunc = deco(myfunc),這裡已經呼叫了deco()函式了。
第二步 :確保裝飾器被呼叫
怎麼解決裝飾器沒有被呼叫的問題呢
# -*- coding:gbk -*-
'''示例2: 使用內嵌包裝函式來確保每次新函式都被呼叫,
內嵌包裝函式的形參和返回值與原函式相同,裝飾函式返回內嵌包裝函式物件'''
def deco(func):
def _deco():
print("before myfunc() called.")
func()
print(" after myfunc() called.")
# 不需要返回func,實際上應返回原函式的返回值
return _deco
@deco
def myfunc():
print(" myfunc() called.")
return 'ok'
myfunc()
myfunc()
這裡其實不需要我解釋了,還是按照第一步中的方法做替換就可以了。還是囉嗦幾句吧。。
@deco 替換為myfunc = deco(myfunc)
程式首先呼叫deco(myfunc),得到的返回結果賦值給了myfunc ,這樣myfunc 就變成了指向函式_deco()的指標
以後的myfunc(),其實是呼叫_deco()
第三步 :對帶引數的函式進行裝飾
破案過程和第一步、第二步完全一致,不再重複了
# -*- coding:gbk -*-
'''示例5: 對帶引數的函式進行裝飾,
內嵌包裝函式的形參和返回值與原函式相同,裝飾函式返回內嵌包裝函式物件'''
def deco(func):
def _deco(a, b):
print("before myfunc() called.")
ret = func(a, b)
print(" after myfunc() called. result: %s" % ret)
return ret
return _deco
@deco
def myfunc(a, b):
print(" myfunc(%s,%s) called." % (a, b))
return a + b
myfunc(1, 2)
myfunc(3, 4)
第四步 :讓裝飾器帶引數
# -*- coding:gbk -*-
'''示例7: 在示例4的基礎上,讓裝飾器帶引數,
和上一示例相比在外層多了一層包裝。
裝飾函式名實際上應更有意義些'''
def deco(arg):
def _deco(func):
def __deco():
print("before %s called [%s]." % (func.__name__, arg))
func()
print(" after %s called [%s]." % (func.__name__, arg))
return __deco
return _deco
@deco("mymodule")
def myfunc():
print(" myfunc() called.")
@deco("module2")
def myfunc2():
print(" myfunc2() called.")
myfunc()
myfunc2()
這種帶引數的裝飾器怎麼解釋呢。其實是一樣的,還是我們的替換操作
@deco("mymodule")替換為myfunc = deco("mymodule")(myfunc )
注意啊,這裡deco後面跟了兩個括號。
有同學要問了,這是什麼意思?
其實很簡單,先執行deco("mymodule"),返回結果為_deco
再執行_deco(myfunc),得到的返回結果為__deco
所以myfunc = __deco
python裝飾器原理 Python裝飾器原理
裝飾器 decorator 是物件導向設計模式的一種,這種模式的核心思想是在不改變原來核心業務邏輯 的情況下,對函式或類物件進行額外的修飾。python中的裝飾器由python直譯器直接支援,其定義形式如下 decorator def core service 要理解上述 的含義,我們從自定義函式裝...
python簡單裝飾器 python裝飾器簡單使用
理解裝飾前先理解python閉包的概念 下面是對裝飾器的簡單舉例 實質 是乙個函式 引數 是你要裝飾的函式名 並非函式呼叫 返回 是裝飾完的函式名 inner 作用 為已經存在的物件新增額外的功能 特點 不需要對物件做任何的 上的變動 被裝飾的函式無引數 def decorate func 裝飾器列...
Python裝飾器的原理與應用
裝飾器是什麼東西呢?就是起到裝飾作用的這麼乙個函式,那這玩意有啥用呢?很多人都會丟擲這樣的疑問,咱們就通俗的說一下這個裝飾器到底是什麼東西,是什麼工作原理呢?首先,裝飾顧名思義就是裝飾用,為什麼需要對函式裝飾呢?是因為要遵循乙個 開放 封閉 原則,因為已經寫好的函式可能已經經過很久的測試和應用,沒有...