在python中使用裝飾器可以在不修改**的前提下為已有的函式新增新功能. 例如計算函式的執行時間, 列印函式的執行日誌, 快取資料, 使用者授權等.
為什麼需要把某個功能用裝飾器的方式實現? 換句話說, 為什麼不直接在函式中實現某個功能? 或者為什麼不單獨用乙個類(class)來實現某個功能, 然後在函式中呼叫?
以提供快取功能的裝飾器為例. 假如我們的業務**負責向資料庫讀取資料, 然後返回給使用者. 為了縮短響應時間, 我們可以把資料放在快取, 從而降低io. 站在業務的角度, 快取功能實際上與我們需要實現的業務功能無關. 為了保持業務**的簡潔, 我們可以把通用的與業務邏輯無關的功能用裝飾器來實現, 即面向切面程式設計的思想.
我們想實現乙個計時的裝飾器timer
. 使用效果如下所示:
# main.py
import time
@timer
deftest()
: time.sleep(
1.0)
if __name__ ==
'__main__'
: test(
)
time cost: 1.0013980865478516
裝飾器timer
的輸入引數是乙個函式物件, 返回的結果也是乙個函式物件. 返回的函式是乙個「附加了新功能的」函式. 在上面的例子中, 裝飾器@timer
實際上是乙個執行如下操作的語法糖.
)完整**
import time
# 裝飾器函式
deftimer
(func)
:# 呼叫func並計時
def(
*args,
**kwargs)
: t1 = time.time(
) func(
*args,
**kwargs)
print
("time cost:"
, time.time(
)- t1)
@timer
deftest()
: time.sleep(
1.0)
if __name__ ==
'__main__'
: test(
)
裝飾後的函式名
>>
>
print
(test.__name__)
import time
from functools import wraps
# 裝飾器函式
deftimer
(func)
:# 呼叫func並計時
@wraps(func)
# 保持func的函式名
def(
*args,
**kwargs)
: t1 = time.time(
) func(
*args,
**kwargs)
print
("time cost:"
, time.time(
)- t1)
下面我們要把計時器的功能稍微擴充一下. 實現乙個帶引數的計時器@timer_unit(unit)
, 其中引數unit代表了計時的單位:'s' -- 秒; 'ms' -- 毫秒
. 前文提到裝飾器函式的輸入必須是乙個函式物件, 否則如何接收函式物件? 注意到函式名加括號timer_unit(unit='s')
代表執行乙個函式, 因此我們只需要讓函式timer_unit(unit='s')
的執行結果返回乙個普通的裝飾器即可.
# 帶引數的裝飾器
deftimer_unit
(unit=
's')
:# 普通裝飾器
defdecorator
(func)
:# 呼叫func並計時
@wraps(func)
# 保持func的函式名
def(
*args,
**kwargs)
: t1 = time.time(
) func(
*args,
**kwargs)
multiplier =
1if unit ==
'ms'
: multiplier =
1000
print
("time cost (unit: %s):"
% unit,
(time.time(
)- t1)
* multiplier)
# 返回普通裝飾器
return decorator
import time
from functools import wraps
class
timer
(object):
""" 乙個用來計時的裝飾器類
需要實現__call__方法, 可以像函式一樣呼叫例項
"""def__init__
(self)
: self._multiplier =
1# 秒
self._unit =
none
# 's'-秒; 'ms'-毫秒; 'mus' - 微秒
def_get_multiplier
(self)
:if self._unit ==
'ms'
:# 毫秒
self._multiplier =
1000
if self._unit ==
'mus'
:# 微秒
self._multiplier =
1000000
return self._multiplier
def__call__
(self, unit=
's')
: self._unit = unit
defdecorator
(func)
:
@wraps(func)
def(
*args,
**kwargs)
: t1 = time.time(
) func(
*args,
**kwargs)
print
("time cost (unit: %s):"
% unit,
(time.time(
)- t1)
* self._get_multiplier())
return decorator
# 裝飾器函式
timer_class = timer(
)@timer_class(unit=
'mus'
)def
test()
: time.sleep(1)
if __name__ ==
'__main__'
: test(
)
python裝飾器 Python 裝飾器
簡言之,python裝飾器就是用於拓展原來函式功能的一種函式,這個函式的特殊之處在於它的返回值也是乙個函式,使用python裝飾器的好處就是在不用更改原函式的 前提下給函式增加新的功能。一般而言,我們要想拓展原來函式 最直接的辦法就是侵入 裡面修改,例如 這是我們最原始的的乙個函式,然後我們試圖記錄...
python裝飾器 裝飾器
由於函式也是乙個物件,而且函式物件可以被賦值給變數,所以,通過變數也能呼叫該函式。def now print 2015 3 25 f now f 2015 3 25 函式物件有乙個 name 屬性,可以拿到函式的名字 now.name now f.name now 現在,假設我們要增強now 函式的...
python裝飾器原理 Python裝飾器原理
裝飾器 decorator 是物件導向設計模式的一種,這種模式的核心思想是在不改變原來核心業務邏輯 的情況下,對函式或類物件進行額外的修飾。python中的裝飾器由python直譯器直接支援,其定義形式如下 decorator def core service 要理解上述 的含義,我們從自定義函式裝...