實現乙個簡單的裝飾器

2021-10-07 23:23:27 字數 3768 閱讀 3645

下面示例定義了乙個裝飾器,它會在每次呼叫被裝飾的函式時計時,然後把經過的時間、傳入的引數和呼叫的結果列印出來。

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...