最簡裝飾器緩存
def deco(func):
def wrap(*args, **kwargs):
return func(*args, **kwargs)
return wrap
def foo(a, b):
return a ** b
原理app
對比被裝飾先後的 foo.__name__
和 foo.__doc__
函數
from functools import wraps
def deco(func):
'''i am deco'''
def wrap(*args, **kwargs):
'''i am wrap'''
return func(*args, **kwargs)
return wrap
簡單過程ui
fn = deco(func)
foo = fn
foo(*args, **kwargs)
多個裝飾器疊加調用的過程spa
def foo(x, y):
return x ** y
# 過程拆解 1
fn3 = deco3(foo)
fn2 = deco2(fn3)
fn1 = deco1(fn2)
foo = fn1
foo(3, 4)
# 過程拆解 2
# 單行: deco1( deco2( deco3(foo) ) )(3, 2)
deco1(
deco2(
deco3(foo)
)
)(3, 4)
帶參數的裝飾器日誌
def deco(n):
def wrap1(func):
def wrap2(*args, **kwargs):
return func(*args, **kwargs)
return wrap2
return wrap1
# 調用過程
wrap1 = deco(n)
wrap2 = wrap1(foo)
foo = wrap2
foo()
# 單行形式
check_result(30)(foo)(4, 8)
裝飾器類和 __call__
code
class Deco:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
return self.func(*args, **kwargs)
def foo(x, y):
return x ** y
# 過程拆解
fn = Deco(foo)
foo = fn
foo(12, 34)
使用場景string
參數、結果檢查it
緩存、計數io
日誌、統計
權限管理
重試
其餘
練習1: 寫一個 timer 裝飾器, 計算出被裝飾函數調用一次花多長時間, 並把時間打印出來
import time
from functools import wraps
def timer(func):
def wrap(*args, **kwargs):
time0 = time.time()
result = func(*args, **kwargs)
time1 = time.time()
print(time1 - time0)
return result
return wrap
練習2: 寫一個 Retry 裝飾器
import time
class retry(object):
def __init__(self, max_retries=3, wait=0, exceptions=(Exception,)):
self.max_retries = max_retries
self.exceptions = exceptions
self.wait = wait
def __call__(self, func):
def wrapper(*args, **kwargs):
for i in range(self.max_retries + 1):
try:
result = func(*args, **kwargs)
except self.exceptions:
time.sleep(self.wait)
continue
else:
return result
return wrapper