Як використовувати python timeit при передачі змінних функціям?


76

Я борюся з цим, використовуючи 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

Якщо я запускаю функцію самостійно, вона працює нормально. Коли я обертаю його в модулі часу, я отримую помилки (я намагався використовувати подвійні лапки та без .. того самого виводу).

будь-які пропозиції були б чудовими!

Дякую!

Відповіді:


128

Зробіть його викличним:

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

Має працювати


Це спрацювало! Дуже дякую. Мені потрібно зрозуміти, що робить лямбда .. здається, це зробило різницю. Спасибі Пабло
Lostsoul

6
якби це десь було в документації
ендоліт

17
О, але лямбда додає трохи накладних витрат, тому не ідеальна для тестування дрібниць. timeit 5*5становить 33 нс, а timeit (lambda: 5*5)()233 нс.
ендоліт

Це ідеально. У мене була проблема просто зателефонувати timeitз лямбда (сценарій завис; метод, яким я вимірював час виконання, це retrbinaryзавантаження через FTP за допомогою ftplib). Як тільки я використав Timerпредмет, він раптом спрацював як шарм. Не знаю, що сталося ...: D
rbaleksandar

23

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

Ви повинні передавати рядок. тобто

t = Timer('superMegaIntenseFunction(10)','from __main__ import superMegaIntenseFunction')

Дякую за відповідь oxtopus! він не працює, коли я обертаю його в лапки, тому його рядок я отримую таку помилку: NameError: глобальне ім'я 'superMegaIntenseFunction' не визначено. Як ви думаєте, що ще я можу спробувати?
Lostsoul

Відповідь виправлено, включивши аргумент налаштування. ( docs.python.org/library/timeit.html#timeit.Timer )
Остін Маршалл

1

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

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

Зверніть увагу, що в цьому випадку накладні витрати часу трохи більші через додаткові виклики функції. [джерело]


0

Одним із способів зробити це було б за допомогою часткового використання, щоб функція "superMegaIntenseFunction" використовувалася як виклична (тобто без ()) у таймері або безпосередньо всередині timeit.timeit. Використання часткового передає аргумент функції, коли його буде викликати таймер.

from functools import partial
from timeit import timeit

print(timeit(partial(superMegaIntenseFunction, 10), number=1))
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.