Документация Python неофициальный перевод

timeit.md

238 строк · 18.4 КБ · обычная страница · сырой текст · скачать

1> **Источник:** https://python-all.ru/3.2/library/timeit.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# 26.4. [`timeit`](https://python-all.ru/3.2/library/timeit.html#module-timeit) – измерение времени выполнения небольших фрагментов кода89**Исходный код:** [Lib/timeit.py](https://python-all.ru/src/3.2/Lib/timeit.py)1011---1213Этот модуль предоставляет простой способ измерения времени выполнения небольших фрагментов кода Python. Он имеет как [*интерфейс командной строки*](https://python-all.ru/3.2/library/timeit.html#command-line-interface), так и [*вызываемый объект*](https://python-all.ru/3.2/library/timeit.html#python-interface). Модуль избегает множества распространённых ловушек при измерении времени выполнения. См. также введение Тима Питерса к главе «Алгоритмы» в *Python Cookbook*, опубликованной O’Reilly.1415## 26.4.1. Базовые примеры1617Следующий пример показывает, как можно использовать [*интерфейс командной строки*](https://python-all.ru/3.2/library/timeit.html#command-line-interface) для сравнения трёх различных выражений:1819```sh20$ python -m timeit '"-".join(str(n) for n in range(100))'2110000 loops, best of 3: 40.3 usec per loop22$ python -m timeit '"-".join([str(n) for n in range(100)])'2310000 loops, best of 3: 33.4 usec per loop24$ python -m timeit '"-".join(map(str, range(100)))'2510000 loops, best of 3: 25.2 usec per loop26```2728Этого можно добиться из [*интерфейса Python*](https://python-all.ru/3.2/library/timeit.html#python-interface) с помощью:2930```python31>>> import timeit32>>> timeit.timeit('"-".join(str(n) for n in range(100))', number=10000)330.818726062774658234>>> timeit.timeit('"-".join([str(n) for n in range(100)])', number=10000)350.728830814361572336>>> timeit.timeit('"-".join(map(str, range(100)))', number=10000)370.585895061492919938```3940Однако обратите внимание, что [`timeit`](https://python-all.ru/3.2/library/timeit.html#module-timeit) автоматически определяет количество повторов только при использовании интерфейса командной строки. В разделе [*Примеры*](https://python-all.ru/3.2/library/timeit.html#timeit-examples) можно найти более сложные примеры.4142## 26.4.2. Интерфейс Python4344Модуль определяет три вспомогательные функции и один открытый класс:4546#### `timeit.timeit(stmt='pass', setup='pass', timer=<default timer>, number=1000000)`4748Создает экземпляр [`Timer`](https://python-all.ru/3.2/library/timeit.html#timeit.Timer) с заданным оператором, кодом *setup* и функцией *timer* и запускает его метод [`timeit()`](https://python-all.ru/3.2/library/timeit.html#timeit.Timer.timeit) с *number* выполнениями.4950#### `timeit.repeat(stmt='pass', setup='pass', timer=<default timer>, repeat=3, number=1000000)`5152Создает экземпляр [`Timer`](https://python-all.ru/3.2/library/timeit.html#timeit.Timer) с заданным оператором, кодом *setup* и функцией *timer* и запускает его метод [`repeat()`](https://python-all.ru/3.2/library/timeit.html#timeit.Timer.repeat) с заданным *repeat* и *number* выполнениями.5354#### `timeit.default_timer()`5556Определяет таймер по умолчанию платформенно-зависимым образом. В Windows [`time.clock()`](https://python-all.ru/3.2/library/time.html#time.clock) имеет микросекундную точность, а [`time.time()`](https://python-all.ru/3.2/library/time.html#time.time) – точность 1/60 секунды. В Unix [`time.clock()`](https://python-all.ru/3.2/library/time.html#time.clock) имеет точность 1/100 секунды, а [`time.time()`](https://python-all.ru/3.2/library/time.html#time.time) гораздо точнее. На любой платформе [`default_timer()`](https://python-all.ru/3.2/library/timeit.html#timeit.default_timer) измеряет реальное время (wall clock time), а не процессорное. Это означает, что другие процессы, запущенные на том же компьютере, могут повлиять на замеры.5758#### `class timeit.Timer(stmt='pass', setup='pass', timer=<timer function>)`5960Класс для измерения скорости выполнения небольших фрагментов кода.6162Конструктор принимает измеряемый оператор, дополнительный оператор, используемый для настройки, и функцию таймера. Оба оператора по умолчанию равны `'pass'`; функция таймера зависит от платформы (см. строку документации модуля). *stmt* и *setup* могут также содержать несколько операторов, разделенных `;` или переводами строк, при условии, что они не содержат многострочных строковых литералов.6364Для измерения времени выполнения первого оператора используйте метод [`timeit()`](https://python-all.ru/3.2/library/timeit.html#timeit.Timer.timeit). Метод [`repeat()`](https://python-all.ru/3.2/library/timeit.html#timeit.Timer.repeat) – это удобная функция для вызова [`timeit()`](https://python-all.ru/3.2/library/timeit.html#timeit.Timer.timeit) несколько раз и возврата списка результатов.6566Параметры *stmt* и *setup* также могут принимать вызываемые объекты без аргументов. Это встраивает вызовы к ним в функцию таймера, которая затем выполняется с помощью [`timeit()`](https://python-all.ru/3.2/library/timeit.html#timeit.Timer.timeit). Обратите внимание, что накладные расходы на измерение времени в этом случае немного больше из-за дополнительных вызовов функций.6768#### `timeit(number=1000000)`6970Измеряет время выполнения основного оператора *number* раз. Сначала выполняется оператор setup один раз, затем возвращается время, затраченное на выполнение основного оператора указанное количество раз, измеряемое в секундах в виде числа с плавающей запятой. Аргумент number – количество повторений цикла, по умолчанию миллион. Основной оператор, оператор setup и используемая функция таймера передаются конструктору.7172> **Примечание**73>74> По умолчанию [`timeit()`](https://python-all.ru/3.2/library/timeit.html#timeit.Timer.timeit) временно отключает [*сборку мусора*](https://python-all.ru/3.2/glossary.html#term-garbage-collection) во время измерения. Преимущество этого подхода в том, что он делает независимые измерения более сопоставимыми. Недостаток – сборка мусора может быть важной составляющей производительности измеряемой функции. Если это так, сборку мусора можно снова включить в качестве первой инструкции в строке *setup*. Например:75>76> ```python77> timeit.Timer('for i in range(10): oct(i)', 'gc.enable()').timeit()78> ```7980#### `repeat(repeat=3, number=1000000)`8182Вызывает [`timeit()`](https://python-all.ru/3.2/library/timeit.html#timeit.Timer.timeit) несколько раз.8384Это удобная функция, которая многократно вызывает [`timeit()`](https://python-all.ru/3.2/library/timeit.html#timeit.Timer.timeit), возвращая список результатов. Первый аргумент указывает, сколько раз вызвать [`timeit()`](https://python-all.ru/3.2/library/timeit.html#timeit.Timer.timeit). Второй аргумент задает параметр *number* для [`timeit()`](https://python-all.ru/3.2/library/timeit.html#timeit.Timer.timeit).8586> **Примечание**87>88> Может возникнуть соблазн вычислить среднее и стандартное отклонение из вектора результатов и сообщить эти значения. Однако это не очень полезно. В типичном случае наименьшее значение дает нижнюю границу того, насколько быстро машина может выполнить заданный фрагмент кода; более высокие значения в векторе результатов обычно вызваны не изменчивостью скорости Python, а другими процессами, мешающими точности измерения времени. Таким образом, [`min()`](https://python-all.ru/3.2/library/functions.html#min) результата – вероятно, единственное число, которое представляет интерес. После этого следует рассмотреть весь вектор и применить здравый смысл, а не статистику.8990#### `print_exc(file=None)`9192Вспомогательная функция для вывода трассировки из кода, время выполнения которого измеряется.9394Типичное использование:9596```python97t = Timer(...)       # за пределами try/except98try:99    t.timeit(...)    # или t.repeat(...)100except:101    t.print_exc()102```103104Преимущество по сравнению со стандартной трассировкой заключается в том, что исходные строки в скомпилированном шаблоне будут отображены. Необязательный аргумент *file* указывает, куда отправляется трассировка; по умолчанию это [`sys.stderr`](https://python-all.ru/3.2/library/sys.html#sys.stderr).105106## 26.4.3. Интерфейс командной строки107108При вызове как программы из командной строки используется следующая форма:109110```python111python -m timeit [-n N] [-r N] [-s S] [-t] [-c] [-h] [statement ...]112```113114Где поддерживаются следующие параметры:115116#### `-n N, --number=N`117118сколько раз выполнять 'statement'119120#### `-r N, --repeat=N`121122сколько раз повторять таймер (по умолчанию 3)123124#### `-s S, --setup=S`125126оператор, выполняемый один раз вначале (по умолчанию `pass`)127128#### `-t, --time`129130использует [`time.time()`](https://python-all.ru/3.2/library/time.html#time.time) (по умолчанию на всех платформах, кроме Windows)131132#### `-c, --clock`133134использует [`time.clock()`](https://python-all.ru/3.2/library/time.html#time.clock) (по умолчанию в Windows)135136#### `-v, --verbose`137138выводить необработанные результаты замера; для большей точности (больше знаков) повторите параметр139140#### `-h, --help`141142вывести краткое сообщение об использовании и выйти143144Многострочный оператор можно задать, указав каждую строку как отдельный аргумент оператора; строки с отступами возможны, если заключить аргумент в кавычки и использовать начальные пробелы. Несколько параметров [*-s*](https://python-all.ru/3.2/library/timeit.html#cmdoption-timeit-s) обрабатываются аналогично.145146Если [*-n*](https://python-all.ru/3.2/library/timeit.html#cmdoption-timeit-n) не указан, подходящее количество циклов вычисляется путём последовательного перебора степеней 10, пока общее время не достигнет хотя бы 0,2 секунды.147148Измерения с помощью [`default_timer()`](https://python-all.ru/3.2/library/timeit.html#timeit.default_timer) могут зависеть от других программ, работающих на том же компьютере, поэтому лучший способ при необходимости точных замеров – повторить измерение несколько раз и использовать лучшее время. Опция [*-r*](https://python-all.ru/3.2/library/timeit.html#cmdoption-timeit-r) подходит для этого; значения по умолчанию – 3 повторения, скорее всего, достаточно в большинстве случаев. В Unix можно использовать [`time.clock()`](https://python-all.ru/3.2/library/time.html#time.clock) для измерения процессорного времени.149150> **Примечание**151>152> Существует некоторая базовая накладная нагрузка, связанная с выполнением инструкции pass. Приведённый здесь код не пытается её скрыть, но о ней следует знать. Базовую накладную нагрузку можно измерить, вызвав программу без аргументов, и она может отличаться в разных версиях Python.153154## 26.4.4. Примеры155156Можно указать инструкцию настройки, которая выполняется только один раз в начале:157158```sh159$ python -m timeit -s 'text = "sample string"; char = "g"'  'char in text'16010000000 loops, best of 3: 0.0877 usec per loop161$ python -m timeit -s 'text = "sample string"; char = "g"'  'text.find(char)'1621000000 loops, best of 3: 0.342 usec per loop163```164165```python166>>> import timeit167>>> timeit.timeit('char in text', setup='text = "sample string"; char = "g"')1680.41440500499993504169>>> timeit.timeit('text.find(char)', setup='text = "sample string"; char = "g"')1701.7246671520006203171```172173То же самое можно сделать с помощью класса [`Timer`](https://python-all.ru/3.2/library/timeit.html#timeit.Timer) и его методов:174175```python176>>> import timeit177>>> t = timeit.Timer('char in text', setup='text = "sample string"; char = "g"')178>>> t.timeit()1790.3955516149999312180>>> t.repeat()181[0.40193588800002544, 0.3960157959998014, 0.39594301399984033]182```183184Следующие примеры показывают, как замерять выражения, содержащие несколько строк. Здесь мы сравниваем затраты на использование [`hasattr()`](https://python-all.ru/3.2/library/functions.html#hasattr) и [`try`](https://python-all.ru/3.2/reference/compound_stmts.html#try)/[`except`](https://python-all.ru/3.2/reference/compound_stmts.html#except) для проверки отсутствующих и присутствующих атрибутов объектов:185186```sh187$ python -m timeit 'try:' '  str.__bool__' 'except AttributeError:' '  pass'188100000 loops, best of 3: 15.7 usec per loop189$ python -m timeit 'if hasattr(str, "__bool__"): pass'190100000 loops, best of 3: 4.26 usec per loop191192$ python -m timeit 'try:' '  int.__bool__' 'except AttributeError:' '  pass'1931000000 loops, best of 3: 1.43 usec per loop194$ python -m timeit 'if hasattr(int, "__bool__"): pass'195100000 loops, best of 3: 2.23 usec per loop196```197198```python199>>> import timeit200>>> # атрибут отсутствует201>>> s = """\202... try:203...     str.__bool__204... except AttributeError:205...     pass206... """207>>> timeit.timeit(stmt=s, number=100000)2080.9138244460009446209>>> s = "if hasattr(str, '__bool__'): pass"210>>> timeit.timeit(stmt=s, number=100000)2110.5829014980008651212>>>213>>> # атрибут присутствует214>>> s = """\215... try:216...     int.__bool__217... except AttributeError:218...     pass219... """220>>> timeit.timeit(stmt=s, number=100000)2210.04215312199994514222>>> s = "if hasattr(int, '__bool__'): pass"223>>> timeit.timeit(stmt=s, number=100000)2240.08588060699912603225```226227Чтобы предоставить модулю [`timeit`](https://python-all.ru/3.2/library/timeit.html#module-timeit) доступ к функциям, которые вы определяете, можно передать параметр *setup*, содержащий инструкцию import:228229```python230def test():231    """Глупая тестовая функция"""232    L = [i for i in range(100)]233234if __name__ == '__main__':235    import timeit236    print(timeit.timeit("test()", setup="from __main__ import test"))237```238