一个简单场景:我有一个给函数计时的装饰器,现在我想给函数运行的时间添加一个时间偏移量time_lag,该时间偏移量不是常数,想通过把该参数传入装饰器中来实现。
- 实现方式1:
import time
from functools import wraps
def timer_func(func,time_lag):
@wraps(func)
def wer(*args,**kwargs):
t1=time.time()
r=func(*args,**kwargs)
t2=time.time()
cost=t2-t1+time_lag
print('time cost %s'%cost)
return r
return wer
def func(n:int):
while n>0:
n=n-1
return n
a=timer_func(func,time_lag=10)
a(1000000)
但是这样的实现方式,就无法语法糖@,每次都要通过函数调用来实现,就失去了装饰器简明、方便的特点了。
因此用另一种实现方式,只需要在原有装饰函数外面再嵌套一层外函数,将想传入装饰器的函数传入最外层函数即可,实现方式如下:
- 实现方式2:
from functools import wraps
import time
def timer(time_lag):
def decorator(func):
@wraps(func)
def wer(*args, **kwargs):
t1 = time.time()
r = func(*args, **kwargs)
t2 = time.time()
cost = t2 - t1
res=cost+time_lag
print('time cost %s' % res)
return func(*args, **kwargs)#返回函数本身结果
return wer#返回内函数
return decorator#返回外函数
def func(n:int):
'''
this is a func test
:param n:
:return:
'''
while n>0:
n=n-1
return n
>>>a=timer(10)#返回外函数,#传入time_lag=10
>>>print(a)
<function timer.<locals>.decorator at 0x000002027D8E5E50>
>>>b=a(func)#返回内函数
>>>print(b)
<function func at 0x000002027D9434C0>
>>>c=b(999999)#调用内函数返回结果
>>>print(c)
time cost 10.069796323776245
0
上述逐步调用的过程只是为了清晰的展示,该函数看起来复杂,实际上本质思想还是闭包的思想,只是在装饰器外再嵌套了一层外函数。每个外函数返回的是它的下一级内函数。最内层函数返回的是调用函数的结果。该方式还可以通过语法糖简明的调用:
@timer(10)#传入time_lag=10
def func(n:int):
while n>0:
n=n-1
return n
>>>func(99999)
time cost 10.008002042770386
@timer(20)#传入time_lag=20
def func1(n:int):
while n>0:
n=n-1
return n
>>>func1(22222222)
time cost 21.447203874588013
- 创建一个带参数的日志装饰器
创建一个日志装饰器,该日志的输出等级、名称、信息通过传参传入装饰器中
def logged(level,name=None,message=None):
def decorator(func):
logname=name if name else func.__module__
log=logging.getLogger(logname)
logmsg=message if message else func.__name__
@wraps(func)
def wraper(*args,**kwargs):
log.log(level,message)
return func(*args,**kwargs)
return wraper
return decorator
@logged(logging.DEBUG,'test_name')
def func(a):
return a+1
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。