Python 时间测量函数
我想写一个Python函数,用来测试每个函数花费的时间,并打印出函数的名字和它所花的时间。我该怎么打印出函数的名字?如果有其他方法也请告诉我。
def measureTime(a):
start = time.clock()
a()
elapsed = time.clock()
elapsed = elapsed - start
print "Time spent in (function name) is: ", elapsed
13 个回答
我觉得timeit
模块没什么问题。这可能是最简单的方法了。
import timeit
timeit.timeit(a, number=1)
你还可以给函数传递参数。只需要用装饰器把你的函数包裹起来就行。想了解更多,可以看看这里:http://www.pythoncentral.io/time-a-python-function/
你可能只想自己写计时代码的情况是,你只想运行一次函数,并且还想得到它的返回值。
使用timeit
模块的好处是,它可以让你设置执行的次数。这样做是因为其他进程可能会影响你的计时准确性。所以,你应该多运行几次,然后看看最低的那个值。
在玩弄timeit
模块后,我觉得它的界面不太好看,跟下面两种方法比起来显得不够优雅。
下面的代码是用Python 3写的。
装饰器方法
这个方法和@Mike的方法几乎一样。这里我添加了kwargs
和functools
的包装,让它更好用。
def timeit(func):
@functools.wraps(func)
def new_func(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
elapsed_time = time.time() - start_time
print('function [{}] finished in {} ms'.format(
func.__name__, int(elapsed_time * 1_000)))
return result
return new_func
@timeit
def foobar():
mike = Person()
mike.think(30)
上下文管理器方法
from contextlib import contextmanager
@contextmanager
def timeit_context(name):
start_time = time.time()
yield
elapsed_time = time.time() - start_time
print('[{}] finished in {} ms'.format(name, int(elapsed_time * 1_000)))
比如,你可以这样使用:
with timeit_context('My profiling code'):
mike = Person()
mike.think()
在with
块中的代码会被计时。
总结
使用第一种方法,你可以很方便地注释掉装饰器,得到正常的代码。不过,这种方法只能用来计时一个函数。如果你有一些代码不想变成函数,那你可以选择第二种方法。
比如,现在你有
images = get_images()
big_image = ImagePacker.pack(images, width=4096)
drawer.draw(big_image)
现在你想计时big_image = ...
这一行。如果把它改成一个函数,会变成:
images = get_images()
big_image = None
@timeit
def foobar():
nonlocal big_image
big_image = ImagePacker.pack(images, width=4096)
drawer.draw(big_image)
看起来不太好……如果你在Python 2中,那就没有nonlocal
这个关键字了。
相反,使用第二种方法在这里就非常合适:
images = get_images()
with timeit_context('foobar'):
big_image = ImagePacker.pack(images, width=4096)
drawer.draw(big_image)
首先,我强烈建议你使用一个叫做 性能分析器 的工具,或者至少使用 timeit 这个模块。
不过,如果你想自己写一个计时的方法来学习,这里有个开始的地方,可以用装饰器来实现。
Python 2:
def timing(f):
def wrap(*args):
time1 = time.time()
ret = f(*args)
time2 = time.time()
print '%s function took %0.3f ms' % (f.func_name, (time2-time1)*1000.0)
return ret
return wrap
使用起来非常简单,只需要用 @timing 这个装饰器:
@timing
def do_work():
#code
Python 3:
def timing(f):
def wrap(*args, **kwargs):
time1 = time.time()
ret = f(*args, **kwargs)
time2 = time.time()
print('{:s} function took {:.3f} ms'.format(f.__name__, (time2-time1)*1000.0))
return ret
return wrap
注意,我在这里用 f.func_name
来获取函数名作为字符串(在 Python 2 中),或者在 Python 3 中用 f.__name__
。