Использовать Python `timeit` из программы, но функционировать так же, как командная строка?

Например, документация гласит:

Однако обратите внимание, что timeit будет автоматически определять количество повторений только при использовании интерфейса командной строки.

Есть ли способ вызвать его из скрипта Python и автоматически определить количество повторений, при этом возвращается только самое короткое число?

1 ответ

Решение

Когда вы звоните timeit из командной строки вот так:

python -mtimeit -s'import test' 'test.foo()'

timeit Модуль называется скриптом. В частности, main функция называется:

if __name__ == "__main__":
    sys.exit(main())

Если вы посмотрите на исходный код, вы увидите, что main функция может занять args аргумент:

def main(args=None):    
    if args is None:
        args = sys.argv[1:]

Так что действительно можно бежать timeit из программы с точно таким же поведением, которое вы видите при запуске из CLI. Просто поставь свой args вместо того, чтобы позволить ему быть установленным sys.argv[1:]:

import timeit
import shlex

def foo():
    total = 0
    for i in range(10000):
        total += i**3
    return total

timeit.main(args=shlex.split("""-s'from __main__ import foo' 'foo()'"""))

напечатает что-то вроде

100 loops, best of 3: 7.9 msec per loop

К несчастью, main печатает на консоль, а не возвращает время за цикл. Поэтому, если вы хотите программно использовать результат, возможно, самый простой способ - начать с копирования main функция, а затем ее изменение - изменение кода печати, чтобы вместо возврата usec,


Пример по OP: если вы разместите это в utils_timeit.py:

import timeit
def timeit_auto(stmt="pass", setup="pass", repeat=3):
    """
    http://stackru.com/q/19062202/190597 (endolith)
    Imitate default behavior when timeit is run as a script.

    Runs enough loops so that total execution time is greater than 0.2 sec,
    and then repeats that 3 times and keeps the lowest value.

    Returns the number of loops and the time for each loop in microseconds
    """
    t = timeit.Timer(stmt, setup)

    # determine number so that 0.2 <= total time < 2.0
    for i in range(1, 10):
        number = 10**i
        x = t.timeit(number) # seconds
        if x >= 0.2:
            break
    r = t.repeat(repeat, number)
    best = min(r)
    usec = best * 1e6 / number
    return number, usec

Вы можете использовать его в таких скриптах:

import timeit
import utils_timeit as UT

def foo():
    total = 0
    for i in range(10000):
        total += i**3
    return total

num, timing = UT.timeit_auto(setup='from __main__ import foo', stmt='foo()')
print(num, timing)

Начиная с Python 3.6, timeit.Timer объекты имеют autorange функция, которая показывает, как number определяется для выполнения из командной строки.

Другие вопросы по тегам