Борьба с Python timeit

Я борюсь с функцией timeit в Python, и на более глубоком уровне меня очень расстраивают причуды этой функции. Я надеюсь, что здесь мне помогут с обоими проблемами.

У меня есть сценарий (назовите его my_script.py) с множеством различных определений функций, а затем множество других вещей, которые вычисляются под ними всеми. В частности, я хочу измерить время только для одной из этих функций - назовем ее level_99_function(x). У меня есть большой массив, хранящийся в my_input. Моя первая попытка:

timeit.timeit('f1(x)', setup = 'my_input')

Python возвращает ошибку: NameError: global name 'angle' is not defined.

Теперь моя вторая попытка - сделать следующее:

print timeit.timeit('level_99_function(x)', setup = 'import numpy as np; import my_script.py; x= np.linspace(0,100)')

Это не вызывает никаких ошибок, но проблема двоякая. Во-первых, и это наиболее важно, он все еще не синхронизирует level_99_function (или, может быть, он просто не выводит результат таймера по какой-либо причине?) Во-вторых, оператор import, похоже, запускает весь скрипт при импорте, что требует навсегда из-за всего того, что у меня есть в этом скрипте, кроме моего level_99_function.

Как мне узнать время выполнения рассматриваемой функции? А на более философском уровне, почему в Python такая борьба? У меня уже определены переменная и функция; все, что я хочу сделать, это приурочить этот вызов функции к этой переменной. Было бы неплохо, если бы не пришлось писать сверхдлинную строку кода, или писать несколько строк кода, или импортировать что-то или что-то в этом роде. Это так же просто, как tic и toc в Matlab. Я предполагаю, что соответствующие команды Python будут использовать time.clock () до и после вызова функции, но я читал, что это может быть неточным и вводящим в заблуждение.


person hobscrk777    schedule 11.08.2014    source источник
comment
похоже, что оператор импорта запускает весь скрипт при импорте. Возможно, вам нужна if __name__ == "__main__": защита всего нефункционального кода в вашем модуле. .   -  person Kevin    schedule 11.08.2014
comment
timeit не эквивалентно tic...toc. Если вам нужна функциональность tic...toc, сделайте что-нибудь вроде: start = time.clock(); my_function(); print time.clock() - start   -  person Joel Cornett    schedule 11.08.2014
comment
Re: ваше разочарование: сделайте себе одолжение и вместо этого используйте iPython с его %timeit магией для тестирования ваших вещей. Он превосходит ваниль timeit во многих отношениях. Для остальных вам нужно будет предоставить дополнительный код. Мы можем догадываться, но вы пришли сюда не для этого.   -  person roippi    schedule 11.08.2014
comment
Возможный дубликат Получение глобального имени 'foo' не определено с Python timeit   -  person sds    schedule 20.09.2017


Ответы (2)


Вам не нужно импортировать numpy каждый раз в setup, вместо этого вы можете импортировать функцию и переменные, которые хотите из текущего скрипта, с помощью from __main__ import ..., как показано в примере ниже.

import timeit
import numpy as np

def func1(x):
    pass

def func2(x):
    pass

def func3(x):
    return np.array(x > 1000)


if __name__ == '__main__':
    x = np.arange(10000)

    time = timeit.timeit('func3(x)', setup='from __main__ import func3, x', number=1000)
    print(time)

Блок if __name__ == '__main__' предотвратит запуск кода в операторе if, если вы импортируйте код из другого скрипта, что означает, что вы случайно не запустите свои временные тесты, если импортируете свои функции.

Этот код импортирует только func3 и x. Меня интересуют только func3 (не func1 и func2), и я определил значение для тестирования (я называю его x, но оно эквивалентно вашему my_input). В этом случае вам не нужно импортировать numpy.

Однако я бы полностью посоветовал вам принять во внимание комментарий roippi и использовать IPython. Магический метод %timeit очень и очень полезен.

person Ffisegydd    schedule 11.08.2014
comment
Спасибо за совет всем. Определенно просто собираюсь использовать команду iPython% timeit. - person hobscrk777; 13.08.2014

В качестве к сведению на будущее:

Недавно я представил патч против issue2527, который был зафиксировано несколько дней назад в ветке по умолчанию. Итак, всякий раз, когда 3.5 публично выпущен, вы можете сделать это:

timeit.timeit('level_99_function(x)', globals=globals())

Я знаю, что не так круто, как %timeit от iPython, но гораздо лучше, чем from __main__ import ... ерунда, которую вы должны делать прямо сейчас. Дополнительная информация в документации.

person roippi    schedule 24.08.2014