我想测量执行一个函数所花费的时间。我没时间工作:

import timeit
start = timeit.timeit()
print("hello")
end = timeit.timeit()
print(end - start)

当前回答

你可以使用timeit。

下面是一个示例,说明如何使用Python REPL测试naive_func,该函数接受参数:

>>> import timeit                                                                                         

>>> def naive_func(x):                                                                                    
...     a = 0                                                                                             
...     for i in range(a):                                                                                
...         a += i                                                                                        
...     return a                                                                                          

>>> def wrapper(func, *args, **kwargs):                                                                   
...     def wrapper():                                                                                    
...         return func(*args, **kwargs)                                                                  
...     return wrapper                                                                                    

>>> wrapped = wrapper(naive_func, 1_000)                                                                  

>>> timeit.timeit(wrapped, number=1_000_000)                                                              
0.4458435332577161  

若函数并没有任何参数,那个么就不需要包装函数。

其他回答

这是一种很晚的反应,但也许对某人来说是有目的的。这是一种我认为非常干净的方法。

import time

def timed(fun, *args):
    s = time.time()
    r = fun(*args)
    print('{} execution took {} seconds.'.format(fun.__name__, time.time()-s))
    return(r)

timed(print, "Hello")

请记住,“print”是Python 3中的函数,而不是Python 2.7中的函数。但是,它可以与任何其他功能一起使用。干杯

使用timeit.default_timer而不是timeit.timeit。前者自动提供您的平台和Python版本上可用的最佳时钟:

from timeit import default_timer as timer

start = timer()
# ...
end = timer()
print(end - start) # Time in seconds, e.g. 5.38091952400282

timeit.default_timer被分配给time.time()或time.clock(),具体取决于操作系统。在Python 3.3+default_timer上,所有平台上都有time.perf_counter()。请参见Python-time.cclock()与time.time()-精度?

另请参见:

正在优化代码如何优化速度

我参加聚会已经很晚了,但这种方法以前没有涉及过。当我们想要手动对某段代码进行基准测试时,我们可能需要首先找出哪些类方法占用了执行时间,这有时并不明显。我构建了以下元类来解决这个问题:

from __future__ import annotations

from functools import wraps
from time import time
from typing import Any, Callable, TypeVar, cast

F = TypeVar('F', bound=Callable[..., Any])


def timed_method(func: F, prefix: str | None = None) -> F:
    prefix = (prefix + ' ') if prefix else ''

    @wraps(func)
    def inner(*args, **kwargs):  # type: ignore
        start = time()
        try:
            ret = func(*args, **kwargs)
        except BaseException:
            print(f'[ERROR] {prefix}{func.__qualname__}: {time() - start}')
            raise
        
        print(f'{prefix}{func.__qualname__}: {time() - start}')
        return ret

    return cast(F, inner)


class TimedClass(type):
    def __new__(
        cls: type[TimedClass],
        name: str,
        bases: tuple[type[type], ...],
        attrs: dict[str, Any],
        **kwargs: Any,
    ) -> TimedClass:
        for name, attr in attrs.items():
            if isinstance(attr, (classmethod, staticmethod)):
                attrs[name] = type(attr)(timed_method(attr.__func__))
            elif isinstance(attr, property):
                attrs[name] = property(
                    timed_method(attr.fget, 'get') if attr.fget is not None else None,
                    timed_method(attr.fset, 'set') if attr.fset is not None else None,
                    timed_method(attr.fdel, 'del') if attr.fdel is not None else None,
                )
            elif callable(attr):
                attrs[name] = timed_method(attr)

        return super().__new__(cls, name, bases, attrs)

它允许如下使用:

class MyClass(metaclass=TimedClass):
    def foo(self): 
        print('foo')
    
    @classmethod
    def bar(cls): 
        print('bar')
    
    @staticmethod
    def baz(): 
        print('baz')
    
    @property
    def prop(self): 
        print('prop')
    
    @prop.setter
    def prop(self, v): 
        print('fset')
    
    @prop.deleter
    def prop(self): 
        print('fdel')


c = MyClass()

c.foo()
c.bar()
c.baz()
c.prop
c.prop = 2
del c.prop

MyClass.bar()
MyClass.baz()

它打印:

foo
MyClass.foo: 1.621246337890625e-05
bar
MyClass.bar: 4.5299530029296875e-06
baz
MyClass.baz: 4.291534423828125e-06
prop
get MyClass.prop: 3.814697265625e-06
fset
set MyClass.prop: 3.5762786865234375e-06
fdel
del MyClass.prop: 3.5762786865234375e-06
bar
MyClass.bar: 3.814697265625e-06
baz
MyClass.baz: 4.0531158447265625e-06

它可以与其他答案相结合,以更精确的方式代替time.time。

这种独特的基于类的方法提供了可打印的字符串表示、可自定义的舍入,以及以字符串或浮点形式方便地访问经过的时间。它是用Python 3.7开发的。

import datetime
import timeit


class Timer:
    """Measure time used."""
    # Ref: https://stackoverflow.com/a/57931660/

    def __init__(self, round_ndigits: int = 0):
        self._round_ndigits = round_ndigits
        self._start_time = timeit.default_timer()

    def __call__(self) -> float:
        return timeit.default_timer() - self._start_time

    def __str__(self) -> str:
        return str(datetime.timedelta(seconds=round(self(), self._round_ndigits)))

用法:

# Setup timer
>>> timer = Timer()

# Access as a string
>>> print(f'Time elapsed is {timer}.')
Time elapsed is 0:00:03.
>>> print(f'Time elapsed is {timer}.')
Time elapsed is 0:00:04.

# Access as a float
>>> timer()
6.841332235
>>> timer()
7.970274425

使用探查器模块。它提供了非常详细的概况。

import profile
profile.run('main()')

它输出类似于:

          5 function calls in 0.047 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.000    0.000 :0(exec)
        1    0.047    0.047    0.047    0.047 :0(setprofile)
        1    0.000    0.000    0.000    0.000 <string>:1(<module>)
        0    0.000             0.000          profile:0(profiler)
        1    0.000    0.000    0.047    0.047 profile:0(main())
        1    0.000    0.000    0.000    0.000 two_sum.py:2(twoSum)

我发现它很有启发性。