> **Источник:** https://python-all.ru/3.1/library/timeit.html
>
> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.

---

# 26.4. `timeit` – измерение времени выполнения небольших фрагментов кода

Этот модуль предоставляет простой способ измерения времени выполнения небольших фрагментов кода Python. Он имеет как интерфейс командной строки, так и вызываемый интерфейс. Он позволяет избежать ряда распространённых ловушек при измерении времени выполнения. См. также введение Тима Питерса в главу «Алгоритмы» в книге Python Cookbook, опубликованной O’Reilly.

Модуль определяет следующий открытый класс:

#### `class timeit.Timer(stmt='pass', setup='pass', timer=<timer function>)`

Класс для измерения скорости выполнения небольших фрагментов кода.

Конструктор принимает измеряемый оператор, дополнительный оператор, используемый для настройки, и функцию таймера. Оба оператора по умолчанию равны `'pass'`; функция таймера зависит от платформы (см. строку документации модуля). *stmt* и *setup* могут также содержать несколько операторов, разделённых `;` или символами новой строки, при условии, что они не содержат многострочных строковых литералов.

Для измерения времени выполнения первого оператора используйте метод [`timeit()`](https://python-all.ru/3.1/library/timeit.html#timeit.timeit). Метод [`repeat()`](https://python-all.ru/3.1/library/timeit.html#timeit.repeat) – это удобная функция для вызова [`timeit()`](https://python-all.ru/3.1/library/timeit.html#timeit.timeit) несколько раз и возврата списка результатов.

Параметры *stmt* и *setup* также могут принимать вызываемые объекты без аргументов. Это встраивает вызовы к ним в функцию таймера, которая затем выполняется с помощью [`timeit()`](https://python-all.ru/3.1/library/timeit.html#timeit.timeit). Обратите внимание, что в этом случае накладные расходы на измерение времени немного выше из-за дополнительных вызовов функций.

#### `Timer.print_exc(file=None)`

Вспомогательная функция для вывода трассировки из кода, время выполнения которого измеряется.

Типичное использование:

```python
t = Timer(...)       # за пределами try/except
try:
    t.timeit(...)    # или t.repeat(...)
except:
    t.print_exc()
```

Преимущество перед стандартным traceback в том, что будут отображаться строки исходного кода в скомпилированном шаблоне. Необязательный аргумент *file* определяет, куда отправляется traceback; по умолчанию он отправляется в `sys.stderr`.

#### `Timer.repeat(repeat=3, number=1000000)`

Вызывает [`timeit()`](https://python-all.ru/3.1/library/timeit.html#timeit.timeit) несколько раз.

Это удобная функция, которая многократно вызывает [`timeit()`](https://python-all.ru/3.1/library/timeit.html#timeit.timeit), возвращая список результатов. Первый аргумент указывает, сколько раз вызывать [`timeit()`](https://python-all.ru/3.1/library/timeit.html#timeit.timeit). Второй аргумент задаёт значение параметра *number* для [`timeit()`](https://python-all.ru/3.1/library/timeit.html#timeit.timeit).

> **Примечание**
>
> Может возникнуть соблазн вычислить среднее и стандартное отклонение из вектора результатов и сообщить их. Однако это не очень полезно. В типичном случае наименьшее значение даёт нижнюю границу того, насколько быстро ваша машина может выполнить данный фрагмент кода; более высокие значения в векторе результатов обычно вызваны не изменчивостью скорости Python, а другими процессами, мешающими точности измерения времени. Поэтому [`min()`](https://python-all.ru/3.1/library/functions.html#min) результатов – вероятно, единственное число, которое вас должно интересовать. После этого следует посмотреть на весь вектор и применить здравый смысл, а не статистику.

#### `Timer.timeit(number=1000000)`

Измеряет время выполнения *number* повторений основного оператора. Он выполняет оператор настройки один раз, а затем возвращает время, необходимое для выполнения основного оператора заданное число раз, измеряемое в секундах как число с плавающей запятой. Аргумент – это количество повторений цикла, по умолчанию один миллион. Основной оператор, оператор настройки и используемая функция таймера передаются конструктору.

> **Примечание**
>
> По умолчанию [`timeit()`](https://python-all.ru/3.1/library/timeit.html#timeit.timeit) временно отключает [*сборку мусора*](https://python-all.ru/3.1/glossary.html#term-garbage-collection) во время измерения времени. Преимущество такого подхода в том, что он делает независимые измерения более сопоставимыми. Недостаток в том, что сборка мусора может быть важной составляющей производительности измеряемой функции. Если это так, сборку мусора можно снова включить, указав её в качестве первого оператора в строке *setup*. Например:
>
> ```python
> timeit.Timer('for i in range(10): oct(i)', 'gc.enable()').timeit()
> ```

Модуль также определяет две вспомогательные функции:

#### `timeit.repeat(stmt='pass', setup='pass', timer=<default timer>, repeat=3, number=1000000)`

Создаёт экземпляр

[`Timer`](https://python-all.ru/3.1/library/timeit.html#timeit.Timer)

с указанным оператором, кодом настройки и функцией таймера и запускает его метод

[`repeat()`](https://python-all.ru/3.1/library/timeit.html#timeit.repeat)

с заданным количеством повторений и

*number*

выполнениями.

#### `timeit.timeit(stmt='pass', setup='pass', timer=<default timer>, number=1000000)`

Создаёт экземпляр

[`Timer`](https://python-all.ru/3.1/library/timeit.html#timeit.Timer)

с указанным оператором, кодом настройки и функцией таймера и запускает его метод

[`timeit()`](https://python-all.ru/3.1/library/timeit.html#timeit.timeit)

с

*number*

выполнениями.

## 26.4.1. Интерфейс командной строки

При вызове как программы из командной строки используется следующая форма:

```python
python -m timeit [-n N] [-r N] [-s S] [-t] [-c] [-h] [statement ...]
```

Где поддерживаются следующие параметры:

#### `-n N, --number=N`

сколько раз выполнять 'statement'

#### `-r N, --repeat=N`

сколько раз повторять таймер (по умолчанию 3)

#### `-s S, --setup=S`

оператор, выполняемый один раз вначале (по умолчанию

`pass`

)

#### `-t, --time`

использует

[`time.time()`](https://python-all.ru/3.1/library/time.html#time.time)

(по умолчанию на всех платформах, кроме Windows)

#### `-c, --clock`

использует

[`time.clock()`](https://python-all.ru/3.1/library/time.html#time.clock)

(по умолчанию в Windows)

#### `-v, --verbose`

выводить необработанные результаты замера; для большей точности (больше знаков) повторите параметр

#### `-h, --help`

вывести краткое сообщение об использовании и выйти

Многострочный оператор можно задать, указав каждую строку как отдельный аргумент оператора; строки с отступами возможны, если заключить аргумент в кавычки и использовать начальные пробелы. Несколько параметров [*-s*](https://python-all.ru/3.1/library/timeit.html#cmdoption-timeit-s) обрабатываются аналогично.

Если [*-n*](https://python-all.ru/3.1/library/timeit.html#cmdoption-timeit-n) не указан, подходящее количество циклов вычисляется путём последовательного перебора степеней 10, пока общее время не достигнет хотя бы 0,2 секунды.

Функция таймера по умолчанию зависит от платформы. В Windows [`time.clock()`](https://python-all.ru/3.1/library/time.html#time.clock) имеет микросекундную точность, а [`time.time()`](https://python-all.ru/3.1/library/time.html#time.time) имеет точность 1/60 секунды; в Unix [`time.clock()`](https://python-all.ru/3.1/library/time.html#time.clock) имеет точность 1/100 секунды, а [`time.time()`](https://python-all.ru/3.1/library/time.html#time.time) гораздо точнее. На любой платформе функции таймера по умолчанию измеряют реальное время (wall clock time), а не процессорное время. Это означает, что другие процессы, работающие на том же компьютере, могут влиять на точность измерения. Лучшее, что можно сделать, когда требуется точное измерение, – это повторить измерение несколько раз и использовать наилучшее время. Опция [*-r*](https://python-all.ru/3.1/library/timeit.html#cmdoption-timeit-r) хорошо подходит для этого; значения по умолчанию в 3 повторения, вероятно, достаточно в большинстве случаев. В Unix вы можете использовать [`time.clock()`](https://python-all.ru/3.1/library/time.html#time.clock) для измерения процессорного времени.

> **Примечание**
>
> Существует некоторая базовая накладная нагрузка, связанная с выполнением оператора pass. Приведённый код не пытается её скрыть, но следует знать об этом. Базовую накладную нагрузку можно измерить, вызвав программу без аргументов.

Базовая накладная нагрузка отличается в разных версиях Python! Кроме того, для честного сравнения старых версий Python с Python 2.3 вы можете использовать опцию *-O* для старых версий, чтобы избежать измерения времени выполнения инструкций `SET_LINENO`.

## 26.4.2. Примеры

Вот два примера сеансов (один с использованием командной строки, другой с использованием интерфейса модуля), которые сравнивают стоимость использования [`hasattr()`](https://python-all.ru/3.1/library/functions.html#hasattr) против [`try`](https://python-all.ru/3.1/reference/compound_stmts.html#try)/[`except`](https://python-all.ru/3.1/reference/compound_stmts.html#except) для проверки отсутствующих и существующих атрибутов объектов.

```python
% timeit.py 'try:' '  str.__bool__' 'except AttributeError:' '  pass'
100000 loops, best of 3: 15.7 usec per loop
% timeit.py 'if hasattr(str, "__bool__"): pass'
100000 loops, best of 3: 4.26 usec per loop
% timeit.py 'try:' '  int.__bool__' 'except AttributeError:' '  pass'
1000000 loops, best of 3: 1.43 usec per loop
% timeit.py 'if hasattr(int, "__bool__"): pass'
100000 loops, best of 3: 2.23 usec per loop
```

```python
>>> import timeit
>>> s = """\
... try:
...     str.__bool__
... except AttributeError:
...     pass
... """
>>> t = timeit.Timer(stmt=s)
>>> print("%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000))
17.09 usec/pass
>>> s = """\
... if hasattr(str, '__bool__'): pass
... """
>>> t = timeit.Timer(stmt=s)
>>> print("%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000))
4.85 usec/pass
>>> s = """\
... try:
...     int.__bool__
... except AttributeError:
...     pass
... """
>>> t = timeit.Timer(stmt=s)
>>> print("%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000))
1.97 usec/pass
>>> s = """\
... if hasattr(int, '__bool__'): pass
... """
>>> t = timeit.Timer(stmt=s)
>>> print("%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000))
3.15 usec/pass
```

Чтобы предоставить модулю `timeit` доступ к определённым вами функциям, вы можете передать параметр `setup`, содержащий инструкцию import:

```python
def test():
    "Stupid test function"
    L = [i for i in range(100)]

if __name__=='__main__':
    from timeit import Timer
    t = Timer("test()", "from __main__ import test")
    print(t.timeit())
```
