Использование Python Timeit для расчета времени кода

В этом руководстве вы узнаете, как использовать функцию timeit из модуля timeit Python. Вы узнаете, как синхронизировать простые выражения и функции в Python.

Синхронизация вашего кода может помочь вам оценить время выполнения фрагмента кода, а также определить участки кода, которые необходимо оптимизировать.

Мы начнем с изучения синтаксиса функции timeit в Python. Затем мы напишем примеры кода, чтобы понять, как использовать его для синхронизации блоков кода и функций в вашем модуле Python. Давай начнем.

Как использовать функцию timeit Python

Модуль timeit является частью стандартной библиотеки Python, и вы можете импортировать его:

import timeit

Синтаксис использования функции timeit из модуля timeit показан ниже:

timeit.timeit(stmt, setup, number)

Здесь:

  • stmt — это фрагмент кода, время выполнения которого необходимо измерить. Вы можете указать его как простую строку Python или многострочную строку или передать имя вызываемого объекта.
  • Как следует из названия, setup обозначает фрагмент кода, который необходимо запустить только один раз, часто в качестве предварительного условия для запуска stmt. Например, предположим, что вы вычисляете время выполнения для создания массива NumPy. В этом случае импорт numpy — это код установки, а фактическое создание — это оператор, который должен быть рассчитан по времени.
  • Номер параметра обозначает количество запусков stmt. Значение числа по умолчанию — 1 миллион (1000000), но вы также можете установить для этого параметра любое другое значение по вашему выбору.

Теперь, когда мы изучили синтаксис использования функции timeit(), давайте начнем кодировать несколько примеров.

Синхронизация простых выражений Python

В этом разделе мы попытаемся измерить время выполнения простых выражений Python с помощью timeit.

Запустите Python REPL и выполните следующие примеры кода. Здесь мы вычисляем время выполнения операций возведения в степень и деления пола для 10000 и 100000 прогонов.

Обратите внимание, что мы передаем оператор для хронометража в виде строки Python и используем точку с запятой для разделения различных выражений в операторе.

>>> import timeit
>>> timeit.timeit('3**4;3//4',number=10000)
0.0004020999999738706

>>> timeit.timeit('3**4;3//4',number=100000)
0.0013780000000451764

Запуск Python timeit в командной строке

Вы также можете использовать timeit в командной строке. Вот эквивалент командной строки вызова функции timeit:

$ python-m timeit -n [number] -s [setup] [stmt]
  • python -m timeit означает, что мы запускаем timeit как основной модуль.
  • n — это параметр командной строки, обозначающий, сколько раз должен запускаться код. Это эквивалентно числовому аргументу в вызове функции timeit().
  • Вы можете использовать опцию -s для определения кода установки.

Здесь мы переписываем предыдущий пример, используя эквивалент командной строки:

$ python -m timeit -n 100000 '3**4;3//4'
100000 loops, best of 5: 35.8 nsec per loop

В этом примере мы вычисляем время выполнения встроенной функции len(). Инициализация строки — это код установки, который передается с помощью параметра s.

$ python -m timeit -n 100000 -s "string_1 = 'coding'" 'len(string_1)'
100000 loops, best of 5: 239 nsec per loop

Обратите внимание, что в выходных данных мы получаем время выполнения для лучшего из 5 запусков. Что это значит? Когда вы запускаете timeit из командной строки, параметру повторения r присваивается значение по умолчанию, равное 5. Это означает, что выполнение stmt указанное количество раз повторяется пять раз, и возвращается лучшее время выполнения.

Анализ методов обращения строк с использованием timeit

При работе со строками Python вы можете захотеть обратить их. Двумя наиболее распространенными подходами к обращению строки являются следующие:

  • Использование нарезки строк
  • Использование функции reversed() и метода join()

Обратные строки Python с использованием нарезки строк

Давайте рассмотрим, как работает нарезка строк и как вы можете использовать ее для реверсирования строки Python. Использование синтаксиса некоторая строка[start:stop] возвращает фрагмент строки, начиная с начала индекса и заканчивая индексом stop-1. Возьмем пример.

Рассмотрим следующую строку «Python». Строка имеет длину 6 и список индексов от 0, 1, 2 до 5.

>>> string_1 = 'Python'

Когда вы указываете как начальное, так и конечное значения, вы получаете фрагмент строки, который простирается от начала до конца-1. Следовательно, строка_1[1:4] возвращает ‘й’.

>>> string_1 = 'Python'
>>> string_1[1:4]
'yth'

Когда вы не указываете начальное значение, используется начальное значение по умолчанию, равное нулю, и срез начинается с нулевого индекса и расширяется до упора — 1.

Здесь конечное значение равно 3, поэтому срез начинается с индекса 0 и поднимается до индекса 2.

>>> string_1[:3]
'Pyt'

Когда вы не включаете конечный индекс, вы видите, что срез начинается с начального индекса (1) и продолжается до конца строки.

>>> string_1[1:]
'ython'

Игнорирование начального и конечного значений возвращает фрагмент всей строки.

>>> string_1[::]
'Python'

Создадим срез со значением шага. Установите значения запуска, остановки и шага на 1, 5 и 2 соответственно. Мы получаем фрагмент строки, начинающийся с 1 и заканчивающийся 4 (исключая конечную точку 5), содержащий каждый второй символ.

>>> string_1[1:5:2]
'yh'

Когда вы используете отрицательный шаг, вы можете получить срез, начинающийся с конца строки. С шагом, установленным на -2, string_1[5:2:-2] дает следующий фрагмент:

>>> string_1[5:2:-2]
'nh'

Таким образом, чтобы получить перевернутую копию строки, мы пропускаем начальное и конечное значения и устанавливаем шаг равным -1, как показано ниже:

>>> string_1[::-1]
'nohtyP'

Вкратце: строка[::-1] возвращает обратную копию строки.

Обращение строк с помощью встроенных функций и строковых методов

Встроенная функция reversed() в Python возвращает обратный итератор для элементов строки.

>>> string_1 = 'Python'
>>> reversed(string_1)
<reversed object at 0x00BEAF70>

Таким образом, вы можете пройти через обратный итератор, используя цикл for:

for char in reversed(string_1):
    print(char)

И получить доступ к элементам строки в обратном порядке.

# Output
n
o
h
t
y
P

Затем вы можете вызвать метод join() для обратного итератора с синтаксисом: .join(reversed(some-string)).

Фрагмент кода ниже показывает пару примеров, где разделителем является дефис и пробел соответственно.

>>> '-'.join(reversed(string1))
'n-o-h-t-y-P'
>>> ' '.join(reversed(string1))
'n o h t y P'

Здесь нам не нужен разделитель; поэтому установите разделитель на пустую строку, чтобы получить обратную копию строки:

>>> ''.join(reversed(string1))
'nohtyP'

Использование «.join(reversed(some-string)) возвращает обратную копию строки.

Сравнение времени выполнения с использованием timeit

До сих пор мы изучили два подхода к обращению строк Python. Но кто из них быстрее? Давайте узнаем.

В предыдущем примере, где мы измеряли время простых выражений Python, у нас не было кода настройки. Здесь мы переворачиваем строку Python. В то время как операция обращения строки выполняется столько раз, сколько указано числом, код установки представляет собой инициализацию строки, которая будет выполняться только один раз.

>>> import timeit
>>> timeit.timeit(stmt="string_1[::-1]", setup = "string_1 = 'Python'", number = 100000)
0.04951830000001678
>>> timeit.timeit(stmt = "''.join(reversed(string_1))", setup = "string_1 = 'Python'", number = 100000)
0.12858760000000302

При том же количестве прогонов для реверсирования заданной строки подход с нарезкой строки быстрее, чем использование метода join() и функции reversed().

Синхронизация функций Python с использованием timeit

В этом разделе мы узнаем, как измерять время функций Python с помощью функции timeit. При наличии списка строк следующая функция hasDigit возвращает список строк, содержащих хотя бы одну цифру.

def hasDigit(somelist):
     str_with_digit = []
     for string in somelist:
         check_char = [char.isdigit() for char in string]
         if any(check_char):
            str_with_digit.append(string)
     return str_with_digit

Теперь мы хотели бы измерить время выполнения этой функции Python hasDigit() с помощью timeit.

Давайте сначала определим оператор, который будет синхронизирован (stmt). Это вызов функции hasDigit() со списком строк в качестве аргумента. Далее давайте определим код установки. Можете ли вы угадать, каким должен быть код установки?

Для успешного выполнения вызова функции код установки должен включать следующее:

  • Определение функции hasDigit()
  • Инициализация списка аргументов строк

Давайте определим код установки в строке установки, как показано ниже:

setup = """
def hasDigit(somelist):
    str_with_digit = []
    for string in somelist:
      check_char = [char.isdigit() for char in string]
      if any(check_char):
        str_with_digit.append(string)
    return str_with_digit
thislist=['puffin3','7frost','blue']
     """

Далее мы можем использовать функцию timeit и получить время выполнения функции hasDigit() для 100000 прогонов.

import timeit
timeit.timeit('hasDigit(thislist)',setup=setup,number=100000)
# Output
0.2810094920000097

Заключение

Вы узнали, как использовать функцию Python timeit для определения времени выражений, функций и других вызываемых объектов. Это может помочь вам протестировать свой код, сравнить время выполнения различных реализаций одной и той же функции и многое другое.

Давайте повторим, что мы узнали в этом уроке. Вы можете использовать функцию timeit() с синтаксисом timeit.timeit(stmt=…,setup=…,number=…). В качестве альтернативы вы можете запустить timeit в командной строке, чтобы синхронизировать короткие фрагменты кода.

В качестве следующего шага вы можете изучить, как использовать другие пакеты профилирования Python, такие как line-profiler и memprofiler, для профилирования вашего кода по времени и памяти соответственно.

Далее узнайте, как рассчитать разницу во времени в Python.