Хочешь уверенно проходить IT-интервью?

Мы понимаем, как сложно подготовиться: стресс, алгоритмы, вопросы, от которых голова идёт кругом. Но с AI тренажёром всё гораздо проще.
💡 Почему Т1 тренажёр — это мастхэв?
- Получишь настоящую обратную связь: где затык, что подтянуть и как стать лучше
- Научишься не только решать задачи, но и объяснять своё решение так, чтобы интервьюер сказал: "Вау!".
- Освоишь все этапы собеседования, от вопросов по алгоритмам до диалога о твоих целях.
Зачем листать миллион туториалов? Просто зайди в Т1 тренажёр, потренируйся и уверенно удиви интервьюеров. Мы не обещаем лёгкой прогулки, но обещаем, что будешь готов!
Реклама. ООО «Смарт Гико», ИНН 7743264341. Erid 2VtzqwP8vqy
Перевод публикуется с сокращениями, автор оригинальной статьи Khuyen Tran.
Мотивация
Вы наверняка видели вывод ошибок наподобие показанного ниже:
2 divided by 1 is equal to 2.0.
Traceback (most recent call last):
File "loguru_example.py", line 17, in <module>
divide_numbers(num_list)
File "loguru_example.py", line 11, in divide_numbers
res = division(num1, num2)
File "loguru_example.py", line 5, in division
return num1/num2
ZeroDivisionError: division by zero
и хотели, чтобы его было немного легче понять:

Возможно, вам даже захочется визуализировать, какие строки кода выполняются и сколько раз:

Если так, статья даст необходимые инструменты, чтобы достичь цели:
- Loguru – вывод сработавших исключений;
- snoop – печать строк кода, выполняемого в функции;
- heartrate – визуализация выполнения программы в режиме реального времени.
Все, что нужно для использования этих инструментов – одна строка кода!
Loguru
Loguru – это библиотека, которая сделает общение с системой журналов в Python приятнее. Она предоставляет много интересных функций, но одна из них заслуживает отдельного внимания – возможность отлавливать неожиданные ошибки и отображать, какое значение переменной приводит к сбою кода.
Установить Loguru можно одной командой:
pip install loguru
Чтобы понять, чем Loguru может быть вам полезна, представьте, что есть 2 функции – division и divide_numbers, при этом функция divide_numbers сейчас выполняется.
from itertools import combinations
def division(num1: int, num2: int):
return num1/num2
def divide_numbers(num_list: list):
"""Division of 2 numbers in the number list """
for comb in combinations(num_list, 2):
num1, num2 = comb
res = division(num1, num2)
print(f"{num1} divided by {num2} is equal to {res}.")
if __name__ =='__main__':
num_list = [2, 1, 0]
divide_numbers(num_list)
Обратите внимание, что комбинации ([2,1,0], 2) возвращают [(2, 1), (2, 0), (1, 0)]. После выполнения приведенного выше кода мы получим следующую ошибку:
2 divided by 1 is equal to 2.0.
Traceback (most recent call last):
File "loguru_example.py", line 17, in <module>
divide_numbers(num_list)
File "loguru_example.py", line 11, in divide_numbers
res = division(num1, num2)
File "loguru_example.py", line 5, in division
return num1/num2
ZeroDivisionError: division by zero
Из выходных данных становится ясно, что возвращающая num1/num2 строка является местом возникновения ошибки, но непонятно, какие значения num1 и num2 ее вызывают. Это можно легко отследить, добавив декоратор Loguru.catch:
from loguru import logger
from itertools import combinations
def division(num1: int, num2: int):
return num1/num2
@logger.catch # Add this to track errors
def divide_numbers(num_list: list):
for comb in combinations(num_list, 2):
num1, num2 = comb
res = division(num1, num2)
print(f"{num1} divided by {num2} is equal to {res}.")
if __name__ =='__main__':
num_list = [2, 1, 0]
divide_numbers(num_list)
Вывод:

Добавив logger.catch исключения гораздо проще понять: ошибка возникает при делении 2 на 0.
Snoop
Как быть, если в коде нет ошибки, но мы хотим выяснить, что в нем происходит? В этом случае пригодится snoop. Это пакет Python, который выводит на экран строки выполняемого кода вместе со значениями каждой переменной, добавляя только один декоратор.
Чтобы установить snoop, введите следующую команду:
pip install snoop
Представим, что у нас есть функция под названием factorial, которая находит факториал целого числа:
import snoop
def factorial(x: int):
if x == 1:
return 1
else:
return (x * factorial(x-1))
if __name__ == "__main__":
num = 5
print(f"The factorial of {num} is {factorial(num)}")
Вывод:
The factorial of 5 is 120
Чтобы понять, почему результат factorial(5) равен 20, добавим декоратор snoop в функцию factorial.
import snoop
@snoop
def factorial(x):
if x == 1:
return 1
else:
return (x * factorial(x-1))
if __name__ == "__main__":
num = 5
print(f"The factorial of {num} is {factorial(num)}")
Вывод:

В приведенном выше выводе можно просмотреть значения переменных, и какие строки кода выполняются. Теперь легче понять, как работает рекурсия.
Heartrate
Если необходимо визуализировать, какие строки и сколько раз выполняются, попробуйте heartrate.
Heartrate также создан разработчиками snoop. Чтобы его установить, введите команду:
pip install heartrate
Теперь добавим heartrate.trace(browser=True) в предыдущий код. Это откроет отображающее визуализацию файла окно браузера, в котором была вызвана функция trace():
import heartrate
heartrate.trace(browser=True)
def factorial(x):
if x == 1:
return 1
else:
return (x * factorial(x-1))
if __name__ == "__main__":
num = 5
print(f"The factorial of {num} is {factorial(num)}")
При запуске приведенного выше кода должен открыться новый браузер. Если нет, перейдите на http://localhost:9999 – вы должны увидеть показанный ниже результат:

Диаграммы подсвечивают искомые строки: более длинные полосы означают больше попаданий, а светлые цвета – более свежее изменение.
На приведенной выше иллюстрации мы видим, как выполняется код:
- if x==1 (5 раз)
- return 1 (1 раз)
- return (x * factorial(x-1)) (4 раза)
Вывод имеет смысл, так как начальное значение x равно 5, и функция вызывается повторно до тех пор, пока x не станет равным 1.
Теперь посмотрим, как визуализировать выполнение в режиме реального времени с помощью heartrate. Добавим sleep(0.5), чтобы программа работала немного медленнее, и увеличим num до 20.
import heartrate
from time import sleep
heartrate.trace(browser=True)
def factorial(x):
if x == 1:
return 1
else:
sleep(0.5)
return (x * factorial(x-1))
if __name__ == "__main__":
num = 20
print(f"The factorial of {num} is {factorial(num)}")

Теперь мы можем в режиме реального времени видеть, какие строки кода выполняются, и сколько раз отработала каждая из них.
Заключение
Мы изучили три инструмента для отслеживания и визуализации выполнения кода в Python. Надеемся, что с ними отладка станет для вас менее болезненной. Поскольку эти инструменты требуют только одной строки кода, почему бы не попробовать их в работе? Удачи в обучении!
Дополнительные материалы:
Комментарии