为了展示函数装饰器的多样化能力,让我们来看一种不同的用例。接下来的装饰器将对被装饰数的调用进行计时一一既有单次调用的用时,也有全部调用的总时间。该装饰器应用于两个函数,以便比较列表推导和内置调用的相对速度:
import time, sys
class timer:
def __init__(self, func):
self.func = func
self.all_time = 0
def __call__(self, *args, **kargs):
start = time.perf_counter()
result = self.func(*args, **kargs)
elapsed = time.perf_counter() - start
self.all_time += elapsed
print('%s: %f, %f' % (self.func.__name__, elapsed, self.all_time))
return result
@timer
def listcomp(N):
return [x * 2 for x in range(N)]
force = list if sys.version_info[0] == 3 else (lambda X:X)
@timer
def mapcall(N):
return force(map((lambda x:x * 2), range(N)))
输入:
listcomp(1000000)
listcomp(1000000)
mapcall(1000000)
mapcall(1000000)
日志输出:
listcomp: 0.108877, 0.108877
listcomp: 0.084942, 0.193819
mapcall: 0.137001, 0.137001
mapcall: 0.143745, 0.280745
输出:
[2, 4, 6, 8, ...]
[2, 4, 6, 8, ...]
[2, 4, 6, 8, ...]
[2, 4, 6, 8, ...]
当然了,计时时间随Python系列和测试机器而变化。这里的累计时间作为一个可用的类实例属性出现。通常,当列表推导中没有函数调用时,map
调用几乎比它慢两倍(也可以说,map
对函数调用的需求使其变慢)。
参考文献:
[1] Mark Lutz. Python学习手册[M]. 机械工业出版社, 2018.