Використання Python Timeit для визначення часу коду

У цьому підручнику ви дізнаєтесь, як використовувати функцію timeit із модуля timeit Python. Ви дізнаєтесь, як визначати час простих виразів і функцій у Python.

Вибір часу коду може допомогти вам отримати оцінку часу виконання частини коду, а також визначити розділи коду, які потрібно оптимізувати.

Ми почнемо з вивчення синтаксису функції timeit Python. А потім ми напишемо приклади коду, щоб зрозуміти, як використовувати його для блоків коду та функцій у вашому модулі Python. Давайте почнемо.

Як використовувати функцію Python timeit

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

import timeit

Синтаксис використання функції timeit із модуля timeit такий, як показано нижче:

timeit.timeit(stmt, setup, number)

Тут:

  • stmt — фрагмент коду, час виконання якого потрібно виміряти. Ви можете вказати його як простий рядок Python або багаторядковий рядок, або передати ім’я викликаного.
  • Як випливає з назви, налаштування позначає фрагмент коду, який потрібно запустити лише один раз, часто як передумову для запуску stmt. Наприклад, припустімо, що ви обчислюєте час виконання для створення масиву NumPy. У цьому випадку імпортування numpy є кодом налаштування, а фактичне створення є оператором, який буде заплановано.
  • Номер параметра вказує на кількість запусків stmt. Стандартне значення числа становить 1 мільйон (1 000 000), але ви також можете встановити для цього параметра будь-яке інше значення на свій вибір.

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

Часові прості вирази Python

У цьому розділі ми спробуємо виміряти час виконання простих виразів Python за допомогою timeit.

Запустіть Python REPL і запустіть наведені нижче приклади коду. Тут ми обчислюємо час виконання операцій зведення до степеня та ділення на підлогу для 10 000 і 100 000 прогонів.

Зверніть увагу, що ми передаємо оператор, який має бути хронометрований, як рядок 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, щоб визначити код налаштування.
  Як налаштувати моніторинг часу роботи сайту за допомогою Google Cloud Monitoring?

Тут ми переписуємо попередній приклад, використовуючи еквівалент командного рядка:

$ 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. Використання синтаксису some-string[start:stop] повертає фрагмент рядка, починаючи з початку індексу та продовжуючи до індексу stop-1. Візьмемо приклад.

Розглянемо наступний рядок “Python”. Рядок має довжину 6, а список індексів — від 0, 1, 2 до 5.

>>> string_1 = 'Python'

Коли ви вказуєте початкове та кінцеве значення, ви отримуєте фрагмент рядка, який розширюється від початку до кінця-1. Отже, рядок_1[1:4] повертає ‘yth’.

  Як тимчасово увімкнути режим «Не турбувати» на iPhone

>>> 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() для 100 000 запусків.

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

Висновок

Ви навчилися використовувати функцію timeit Python для визначення часу виразів, функцій та інших викликів. Це може допомогти вам порівняти свій код, порівняти час виконання різних реалізацій однієї функції тощо.

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

Як наступний крок ви можете дослідити, як використовувати інші пакети профілювання Python, такі як line-profiler і memprofiler, для профілювання вашого коду для часу та пам’яті відповідно.

Далі дізнайтеся, як розрахувати різницю в часі в Python.