装饰器
-
最简装饰器
def deco(func):def wrap(*args, **kwargs):return func(*args, **kwargs)return wrapdef foo(a, b):return a ** b -
原理
-
对比被装饰前后的
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 -
简单过程
fn = deco(func)foo = fnfoo(*args, **kwargs) -
多个装饰器叠加调用的过程
def foo(x, y):return x ** y
# 过程拆解 1fn3 = deco3(foo)fn2 = deco2(fn3)fn1 = deco1(fn2)foo = fn1foo(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 wrap2return wrap1
# 调用过程wrap1 = deco(n)wrap2 = wrap1(foo)foo = wrap2foo()
# 单行形式check_result(30)(foo)(4, 8) -
装饰器类和
__call__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 = fnfoo(12, 34) -
使用场景
-
参数、结果检查
-
缓存、计数
-
日志、统计
-
权限管理
-
重试
-
其他
-
-
练习1: 写一个 timer 装饰器, 计算出被装饰函数调用一次花多长时间, 并把时间打印出来
import timefrom functools import wraps
def timer(func):def wrap(*args, **kwargs):time0 = time.time()result = func(*args, **kwargs)time1 = time.time()print(time1 - time0)return resultreturn wrap -
练习2: 写一个 Retry 装饰器
import timeclass retry(object):def __init__(self, max_retries=3, wait=0, exceptions=(Exception,)):self.max_retries = max_retriesself.exceptions = exceptionsself.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)continueelse:return resultreturn wrapper