Python 时间测量函数

139 投票
13 回答
230138 浏览
提问于 2025-04-16 14:40

我想写一个Python函数,用来测试每个函数花费的时间,并打印出函数的名字和它所花的时间。我该怎么打印出函数的名字?如果有其他方法也请告诉我。

def measureTime(a):
    start = time.clock() 
    a()
    elapsed = time.clock()
    elapsed = elapsed - start
    print "Time spent in (function name) is: ", elapsed

13 个回答

14

我觉得timeit模块没什么问题。这可能是最简单的方法了。

import timeit
timeit.timeit(a, number=1)

你还可以给函数传递参数。只需要用装饰器把你的函数包裹起来就行。想了解更多,可以看看这里:http://www.pythoncentral.io/time-a-python-function/

你可能只想自己写计时代码的情况是,你只想运行一次函数,并且还想得到它的返回值。

使用timeit模块的好处是,它可以让你设置执行的次数。这样做是因为其他进程可能会影响你的计时准确性。所以,你应该多运行几次,然后看看最低的那个值。

65

在玩弄timeit模块后,我觉得它的界面不太好看,跟下面两种方法比起来显得不够优雅。

下面的代码是用Python 3写的。

装饰器方法

这个方法和@Mike的方法几乎一样。这里我添加了kwargsfunctools的包装,让它更好用。

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)
270

首先,我强烈建议你使用一个叫做 性能分析器 的工具,或者至少使用 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__

撰写回答