下面示例定義了乙個裝飾器,它會在每次呼叫被裝飾的函式時計時,然後把經過的時間、傳入的引數和呼叫的結果列印出來。
import time
defclock
(func)
:def
clocked
(*args)
:# ➊
t0 = time.perf_counter(
) result = func(
*args)
# ➋ elapsed = time.perf_counter(
)- t0
name = func.__name__
arg_str =
','.join(
repr
(arg)
for arg in args)
print
('[%0.8fs] %s(%s) -> %r'
%(elapsed, name,arg_str,result)
)return result
return clocked # ➌
➊ 定義內部函式clocked,它接受任意個定位引數。
➋ 這行**可用,是因為clocked的閉包中包含自由變數func。
➌ 返回內部函式,取代被裝飾的函式。
#使用clock裝飾器
# clockdeco_demo.py
import time
from clockdeco import clock
@clock
defsnooze
(seconds)
: time.sleep(seconds)
@clock
deffactorial
(n):
return
1if n <
2else n*factorial(n-1)
if __name__==
'__main__'
:print
('*'*40
,'calling snooze(.123)'
) snooze(
.123
)print
('*'*40
,'calling factorial(6)'
)print
('6! ='
, factorial(6)
)
輸出的結果如下
$ python3 clockdeco_demo.py
****
****
****
****
****
****
****
****
****
**** calling snooze(
123)
[0.12405610s] snooze(
.123)-
>
none
****
****
****
****
****
****
****
****
****
**** calling factorial(6)
[0.00000191s] factorial(1)
->1[
0.00004911s] factorial(2)
->2[
0.00008488s] factorial(3)
->6[
0.00013208s] factorial(4)
->24[
0.00019193s] factorial(5)
->
120[
0.00026107s] factorial(6)
->
7206! =
720
記得嗎,如下**:
@clock
def factorial(n):
return 1 if n < 2 else n*factorial(n-1)
其實等價於:
def factorial(n):
return 1 if n < 2 else n*factorial(n-1)
factorial = clock(factorial)
在兩個示例中,factorial會作為func引數傳給clock
然後,clock函式會返回clocked函式,python直譯器在背後會把clocked賦值給factorial。其實,匯入clockdeco_demo模組後檢視factorial的__name__屬性,會得到如下結果:
>>
>
import clockdeco_demo
>>
>> clockdeco_demo.factorial.__name__
'clocked'
>>
>
所以,現在factorial儲存的是clocked函式的引用。自此之後,每次呼叫factorial(n),執行的都是clocked(n)。clocked大致做了下面幾件事。
(1) 記錄初始時間t0。
(2) 呼叫原來的factorial函式,儲存結果。
(3) 計算經過的時間。
(4) 格式化收集的資料,然後列印出來。
(5) 返回第2步儲存的結果。
這是裝飾器的典型行為:把被裝飾的函式替換成新函式,二者接受相同的引數,而且(通常)返回被裝飾的函式本該返回的值,同時還會做些額外操作。
下面的改進示例中使用functools.wraps裝飾器把相關的屬性從func複製到clocked中。functools.wraps只是標準庫中拿來即用的裝飾器之一。此外,這個新版還能正確處理關鍵字引數。
#改進後的clock裝飾器
# clockdeco2.py
import time
import functools
defclock
(func)
: @functools.wraps(func)
defclocked
(*args,
**kwargs)
: t0 = time.time(
) result = func(
*args,
**kwargs)
elapsed = time.time(
)- t0
name = func.__name__
arg_lst =
if args:
', '
.join(
repr
(arg)
for arg in args)
)if kwargs:
pairs =
['%s=%r'
%(k, w)
for k, w in
sorted
(kwargs.items())
] ', '
.join(pairs)
) arg_str =
', '
.join(arg_lst)
print
('[%0.8fs] %s(%s) -> %r '
%(elapsed, name, arg_str, result)
)return result
return clocked
Python實現乙個裝飾器
在不改變原函式的呼叫以及內部 情況下,為其新增新功能的函式。實現乙個裝飾器 def print func name func 提供舊功能 print func.name 新功能 return func args,kwargs 舊功能 print func name say hello print f...
乙個裝飾器裝飾乙個函式
2 如果鍵不存在,則新增到字典中。請使用裝飾器來實現,順便複習下 args和 kwargs的用法 a defselect func def inner args,kwargs if len args 0 if kwargs key in kwargs data print 鍵存在 else func...
乙個裝飾器的簡單應用小例子
登陸驗證 如果沒喲登陸,則提示登陸 message deflogin f def inner args,kwargs 被裝飾函式執行之前的操作 if message status ret f args,kwargs return ret else name input 輸入帳戶 password i...