Как использовать Python Timeit при передаче переменных в функции? - PullRequest
72 голосов
/ 23 сентября 2011

Я борюсь с этим, используя timeit, и мне было интересно, есть ли у кого-нибудь советы

В основном у меня есть функция (которой я передаю значение), которую я хочу проверить на скорость, и я создал это:

if __name__=='__main__':
    from timeit import Timer
    t = Timer(superMegaIntenseFunction(10))
    print t.timeit(number=1)

, но когда я запускаю его, я получаю странные ошибки, такие как поступление из модуля timeit.:

ValueError: stmt is neither a string nor callable

Если я запускаю функцию самостоятельно, она работает нормально.Когда я обертываю его во время модуля, я получаю ошибки (я пробовал использовать двойные кавычки и без ... sameoutput).

любые предложения будут замечательными!

Спасибо!

Ответы [ 5 ]

116 голосов
/ 23 сентября 2011

Сделайте это вызываемым:

if __name__=='__main__':
    from timeit import Timer
    t = Timer(lambda: superMegaIntenseFunction(10))
    print(t.timeit(number=1))

Должно работать

23 голосов
/ 23 сентября 2011

Timer(superMegaIntenseFunction(10)) означает «вызов superMegaIntenseFunction(10), а затем передача результата в Timer».Это явно не то, что вы хотите.Timer ожидает либо вызываемого объекта (так же, как это звучит: что-то, что может быть вызвано, например, функцию), либо строку (чтобы она могла интерпретировать содержимое строки как код Python)Timer работает, повторно вызывая вызываемую вещь и наблюдая, сколько времени уходит.

Timer(superMegaIntenseFunction) пройдет проверку типа, потому что superMegaIntenseFunction вызывается.Однако, Timer не будет знать, какие значения передать superMegaIntenseFunction.

Простой способ обойти это, конечно, - использовать строку с кодом.Нам нужно передать аргумент 'setup' в код, потому что строка «интерпретируется как код» в новом контексте - у нее нет доступа к тому же globals, поэтому вам нужно запустить еще один бит кода длясделать определение доступным - см. ответ @ oxtopus.

С помощью lambda (как в ответе @ Pablo) мы можем связать параметр 10 с вызовом superMegaIntenseFunction.Все, что мы делаем, это создаем другую функцию, которая не принимает аргументов и вызывает superMegaIntenseFunction с 10.Это похоже на то, как если бы вы использовали def для создания другой подобной функции, за исключением того, что новая функция не получает имя (потому что оно ей не нужно).

18 голосов
/ 23 сентября 2011

Вы должны передать строку.т.е.

t = Timer('superMegaIntenseFunction(10)','from __main__ import superMegaIntenseFunction')
1 голос
/ 09 февраля 2017

Записка для будущих посетителей.Если вам нужно, чтобы он работал в pdb отладчике, а superMegaIntenseFunction не входит в глобальную область, вы можете заставить его работать, добавив в globals:

globals()['superMegaIntenseFunction'] = superMegaIntenseFunction
timeit.timeit(lambda: superMegaIntenseFunction(x))

Обратите внимание, чтонакладные расходы в этом случае немного больше из-за дополнительных вызовов функций. [источник]

0 голосов
/ 01 декабря 2018

Один из способов сделать это - использовать частичное, чтобы функция 'superMegaIntenseFunction' использовалась как вызываемая (т.е. без ()) в таймере или непосредственно внутри timeit.timeit. Использование частичного будет передавать аргумент функции, когда он будет вызван таймером.

from functools import partial
from timeit import timeit

print(timeit(partial(superMegaIntenseFunction, 10), number=1))
...