timeit.md
1> **Источник:** https://python-all.ru/2.7/library/timeit.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# 26.6. [`timeit`](https://python-all.ru/2.7/library/timeit.html#module-timeit) – Измерение времени выполнения небольших фрагментов кода89Новое в версии 2.3.1011**Исходный код:** [Lib/timeit.py](https://python-all.ru/src/2.7/Lib/timeit.py)1213---1415Этот модуль предоставляет простой способ измерения времени выполнения небольших фрагментов кода Python. Он имеет как [интерфейс командной строки](https://python-all.ru/2.7/library/timeit.html#timeit-command-line-interface), так и [вызываемый объект](https://python-all.ru/2.7/library/timeit.html#python-interface). Модуль избегает множества распространённых ловушек при измерении времени выполнения. См. также введение Тима Питерса к главе «Алгоритмы» в *Python Cookbook*, опубликованной O’Reilly.1617## 26.6.1. Основные примеры1819Следующий пример показывает, как можно использовать [интерфейс командной строки](https://python-all.ru/2.7/library/timeit.html#timeit-command-line-interface) для сравнения трёх различных выражений:2021```sh22$ python -m timeit '"-".join(str(n) for n in range(100))'2310000 loops, best of 3: 40.3 usec per loop24$ python -m timeit '"-".join([str(n) for n in range(100)])'2510000 loops, best of 3: 33.4 usec per loop26$ python -m timeit '"-".join(map(str, range(100)))'2710000 loops, best of 3: 25.2 usec per loop28```2930Этого можно добиться из [интерфейса Python](https://python-all.ru/2.7/library/timeit.html#python-interface) с помощью:3132```python33>>> import timeit34>>> timeit.timeit('"-".join(str(n) for n in range(100))', number=10000)350.818726062774658236>>> timeit.timeit('"-".join([str(n) for n in range(100)])', number=10000)370.728830814361572338>>> timeit.timeit('"-".join(map(str, range(100)))', number=10000)390.585895061492919940```4142Однако обратите внимание, что [`timeit`](https://python-all.ru/2.7/library/timeit.html#module-timeit) будет автоматически определять количество повторений только при использовании интерфейса командной строки. В разделе [Примеры](https://python-all.ru/2.7/library/timeit.html#timeit-examples) вы можете найти более сложные примеры.4344## 26.6.2. Интерфейс Python4546Модуль определяет три вспомогательные функции и один открытый класс:4748#### `timeit.timeit(stmt='pass', setup='pass', timer=<default timer>, number=1000000)`4950Создаёт экземпляр [`Timer`](https://python-all.ru/2.7/library/timeit.html#timeit.Timer) с заданным выражением, кодом *setup* и функцией *timer* и запускает его метод [`timeit()`](https://python-all.ru/2.7/library/timeit.html#timeit.Timer.timeit) с *number* выполнениями.5152Новое в версии 2.6.5354#### `timeit.repeat(stmt='pass', setup='pass', timer=<default timer>, repeat=3, number=1000000)`5556Создаёт экземпляр [`Timer`](https://python-all.ru/2.7/library/timeit.html#timeit.Timer) с заданным выражением, кодом *setup* и функцией *timer* и запускает его метод [`repeat()`](https://python-all.ru/2.7/library/timeit.html#timeit.Timer.repeat) с указанными количеством повторов *repeat* и числом выполнений *number*.5758Новое в версии 2.6.5960#### `timeit.default_timer()`6162Определяет таймер по умолчанию, в зависимости от платформы. На Windows [`time.clock()`](https://python-all.ru/2.7/library/time.html#time.clock) имеет микросекундную точность, а точность [`time.time()`](https://python-all.ru/2.7/library/time.html#time.time) составляет 1/60 секунды. На Unix [`time.clock()`](https://python-all.ru/2.7/library/time.html#time.clock) имеет точность 1/100 секунды, а [`time.time()`](https://python-all.ru/2.7/library/time.html#time.time) гораздо точнее. На обеих платформах [`default_timer()`](https://python-all.ru/2.7/library/timeit.html#timeit.default_timer) измеряет реальное время (wall clock), а не процессорное. Это означает, что другие процессы, выполняющиеся на том же компьютере, могут влиять на результаты измерений.6364#### `class timeit.Timer(stmt='pass', setup='pass', timer=<timer function>)`6566Класс для измерения скорости выполнения небольших фрагментов кода.6768Конструктор принимает измеряемое выражение, дополнительное выражение для настройки (setup) и функцию таймера. Оба выражения по умолчанию равны `'pass'`; функция таймера зависит от платформы (см. документацию модуля). *stmt* и *setup* могут также содержать несколько выражений, разделённых `;` или переводами строк, при условии, что они не содержат многострочных строковых литералов.6970Чтобы измерить время выполнения первого оператора, используйте метод [`timeit()`](https://python-all.ru/2.7/library/timeit.html#timeit.Timer.timeit). Метод [`repeat()`](https://python-all.ru/2.7/library/timeit.html#timeit.Timer.repeat) – это удобный способ вызвать [`timeit()`](https://python-all.ru/2.7/library/timeit.html#timeit.Timer.timeit) несколько раз и вернуть список результатов.7172Изменено в версии 2.6: Параметры *stmt* и *setup* теперь могут также принимать вызываемые объекты без аргументов. Это приведет к встраиванию вызовов этих объектов в функцию таймера, которая затем будет выполнена [`timeit()`](https://python-all.ru/2.7/library/timeit.html#timeit.Timer.timeit). Обратите внимание, что в этом случае накладные расходы на измерение немного выше из-за дополнительных вызовов функций.7374#### `timeit(number=1000000)`7576Измеряет время выполнения основного оператора *number* раз. Сначала выполняется оператор setup один раз, затем возвращается время, затраченное на выполнение основного оператора указанное количество раз, измеряемое в секундах в виде числа с плавающей запятой. Аргумент number – количество повторений цикла, по умолчанию миллион. Основной оператор, оператор setup и используемая функция таймера передаются конструктору.7778> **Примечание**79>80> По умолчанию [`timeit()`](https://python-all.ru/2.7/library/timeit.html#timeit.Timer.timeit) временно отключает [сборку мусора](https://python-all.ru/2.7/glossary.html#term-garbage-collection) во время замера. Преимущество такого подхода в том, что независимые замеры становятся более сопоставимыми. Недостаток в том, что сборка мусора может быть важной составляющей производительности измеряемой функции. Если это так, сборку мусора можно снова включить, указав её первой инструкцией в строке *setup*. Например:81>82> ```python83> timeit.Timer('for i in xrange(10): oct(i)', 'gc.enable()').timeit()84> ```8586#### `repeat(repeat=3, number=1000000)`8788Вызов [`timeit()`](https://python-all.ru/2.7/library/timeit.html#timeit.Timer.timeit) несколько раз.8990Это удобная функция, которая многократно вызывает [`timeit()`](https://python-all.ru/2.7/library/timeit.html#timeit.Timer.timeit), возвращая список результатов. Первый аргумент указывает, сколько раз вызывать [`timeit()`](https://python-all.ru/2.7/library/timeit.html#timeit.Timer.timeit). Второй аргумент задаёт аргумент *number* для [`timeit()`](https://python-all.ru/2.7/library/timeit.html#timeit.Timer.timeit).9192> **Примечание**93>94> Может возникнуть соблазн вычислить среднее и стандартное отклонение из результирующего вектора и сообщить о них. Однако это не очень полезно. В типичном случае наименьшее значение даёт нижнюю границу того, насколько быстро ваша машина может выполнить данный фрагмент кода; более высокие значения в результирующем векторе обычно вызваны не изменчивостью скорости Python, а другими процессами, влияющими на точность измерения времени. Поэтому [`min()`](https://python-all.ru/2.7/library/functions.html#min) результата – вероятно, единственное число, которое должно интересовать. После этого следует посмотреть на весь вектор и применить здравый смысл, а не статистику.9596#### `print_exc(file=None)`9798Вспомогательная функция для вывода трассировки из кода, время выполнения которого измеряется.99100Типичное использование:101102```python103t = Timer(...) # за пределами try/except104try:105 t.timeit(...) # или t.repeat(...)106except:107 t.print_exc()108```109110Преимущество перед стандартной трассировкой заключается в том, что отображаются строки исходного кода из скомпилированного шаблона. Необязательный аргумент *file* указывает, куда отправляется трассировка; по умолчанию используется [`sys.stderr`](https://python-all.ru/2.7/library/sys.html#sys.stderr).111112## 26.6.3. Интерфейс командной строки113114При вызове как программы из командной строки используется следующая форма:115116```python117python -m timeit [-n N] [-r N] [-s S] [-t] [-c] [-h] [statement ...]118```119120Где поддерживаются следующие параметры:121122#### `-n N, --number=N`123124сколько раз выполнять 'statement'125126#### `-r N, --repeat=N`127128сколько раз повторять таймер (по умолчанию 3)129130#### `-s S, --setup=S`131132инструкция, выполняемая один раз в начале (по умолчанию `pass`)133134#### `-t, --time`135136используется [`time.time()`](https://python-all.ru/2.7/library/time.html#time.time) (по умолчанию на всех платформах, кроме Windows)137138#### `-c, --clock`139140используется [`time.clock()`](https://python-all.ru/2.7/library/time.html#time.clock) (по умолчанию на Windows)141142#### `-v, --verbose`143144выводить необработанные результаты замера; для большей точности (больше знаков) повторите параметр145146#### `-h, --help`147148вывести краткое сообщение об использовании и выйти149150Многострочная инструкция может быть задана указанием каждой строки как отдельного аргумента statement; строки с отступами возможны путём заключения аргумента в кавычки и использования начальных пробелов. Несколько параметров [`-s`](https://python-all.ru/2.7/library/timeit.html#cmdoption-timeit-s) обрабатываются аналогично.151152Если [`-n`](https://python-all.ru/2.7/library/timeit.html#cmdoption-timeit-n) не указано, подходящее количество циклов вычисляется путём перебора последовательных степеней 10, пока общее время не достигнет хотя бы 0,2 секунды.153154Измерения [`default_timer()`](https://python-all.ru/2.7/library/timeit.html#timeit.default_timer) могут зависеть от других программ, работающих на том же компьютере, поэтому при необходимости точного измерения лучше всего повторить замер несколько раз и взять наилучшее время. Опция [`-r`](https://python-all.ru/2.7/library/timeit.html#cmdoption-timeit-r) подходит для этого; значения по умолчанию в 3 повторения, вероятно, достаточно в большинстве случаев. На Unix можно использовать [`time.clock()`](https://python-all.ru/2.7/library/time.html#time.clock) для измерения процессорного времени.155156> **Примечание**157>158> Существует некоторая базовая задержка, связанная с выполнением пустого оператора pass. Код здесь не пытается её скрыть, но о ней следует знать. Базовую задержку можно измерить, вызвав программу без аргументов, и она может различаться в разных версиях Python. Кроме того, для корректного сравнения старых версий Python с Python 2.3 может потребоваться использовать опцию `-O` Python (см. [Оптимизации](https://python-all.ru/2.7/using/cmdline.html#using-on-optimizations)) для старых версий, чтобы избежать измерения инструкций `SET_LINENO`.159160## 26.6.4. Примеры161162Можно указать инструкцию настройки, которая выполняется только один раз в начале:163164```sh165$ python -m timeit -s 'text = "sample string"; char = "g"' 'char in text'16610000000 loops, best of 3: 0.0877 usec per loop167$ python -m timeit -s 'text = "sample string"; char = "g"' 'text.find(char)'1681000000 loops, best of 3: 0.342 usec per loop169```170171```python172>>> import timeit173>>> timeit.timeit('char in text', setup='text = "sample string"; char = "g"')1740.41440500499993504175>>> timeit.timeit('text.find(char)', setup='text = "sample string"; char = "g"')1761.7246671520006203177```178179То же самое можно сделать с помощью класса [`Timer`](https://python-all.ru/2.7/library/timeit.html#timeit.Timer) и его методов:180181```python182>>> import timeit183>>> t = timeit.Timer('char in text', setup='text = "sample string"; char = "g"')184>>> t.timeit()1850.3955516149999312186>>> t.repeat()187[0.40193588800002544, 0.3960157959998014, 0.39594301399984033]188```189190Следующие примеры показывают, как замерять время выполнения выражений, состоящих из нескольких строк. Здесь мы сравниваем затраты на использование [`hasattr()`](https://python-all.ru/2.7/library/functions.html#hasattr) против [`try`](https://python-all.ru/2.7/reference/compound_stmts.html#try)/[`except`](https://python-all.ru/2.7/reference/compound_stmts.html#except) для проверки отсутствующих и существующих атрибутов объектов:191192```sh193$ python -m timeit 'try:' ' str.__nonzero__' 'except AttributeError:' ' pass'194100000 loops, best of 3: 15.7 usec per loop195$ python -m timeit 'if hasattr(str, "__nonzero__"): pass'196100000 loops, best of 3: 4.26 usec per loop197198$ python -m timeit 'try:' ' int.__nonzero__' 'except AttributeError:' ' pass'1991000000 loops, best of 3: 1.43 usec per loop200$ python -m timeit 'if hasattr(int, "__nonzero__"): pass'201100000 loops, best of 3: 2.23 usec per loop202```203204```python205>>> import timeit206>>> # атрибут отсутствует207>>> s = """\208... try:209... str.__nonzero__210... except AttributeError:211... pass212... """213>>> timeit.timeit(stmt=s, number=100000)2140.9138244460009446215>>> s = "if hasattr(str, '__bool__'): pass"216>>> timeit.timeit(stmt=s, number=100000)2170.5829014980008651218>>>219>>> # атрибут присутствует220>>> s = """\221... try:222... int.__nonzero__223... except AttributeError:224... pass225... """226>>> timeit.timeit(stmt=s, number=100000)2270.04215312199994514228>>> s = "if hasattr(int, '__bool__'): pass"229>>> timeit.timeit(stmt=s, number=100000)2300.08588060699912603231```232233Чтобы предоставить модулю [`timeit`](https://python-all.ru/2.7/library/timeit.html#module-timeit) доступ к определяемым вами функциям, можно передать параметр *setup*, содержащий инструкцию import:234235```python236def test():237 """Глупая тестовая функция"""238 L = []239 for i in range(100):240 L.append(i)241242if __name__ == '__main__':243 import timeit244 print(timeit.timeit("test()", setup="from __main__ import test"))245```246