3 инструмента для отслеживания и визуализации выполнения кода на Python
Каждый хотел бы облегчить процесс дебаггинга и избавиться от головной боли. Решаем эту проблему с помощью инструментов для отслеживания выполнения кода на Python. Обсудить Перевод публикуется с сокращениями, автор оригинальной статьи Khuyen Tran. Вы наверняка видели вывод ошибок наподобие показанного ниже: и хотели, чтобы его было немного легче понять: Возможно, вам даже захочется визуализировать, какие строки кода выполняются и сколько раз: Если так, статья даст необходимые инструменты, чтобы достичь цели: Все, что нужно для использования этих инструментов – одна строка кода! Loguru – это библиотека, которая сделает общение с системой журналов в Python приятнее. Она предоставляет много интересных функций, но одна из них заслуживает отдельного внимания – возможность отлавливать неожиданные ошибки и отображать, какое значение переменной приводит к сбою кода. Установить Loguru можно одной командой: Чтобы понять, чем Loguru может быть вам полезна, представьте, что есть 2 функции – division и divide_numbers, при этом функция divide_numbers сейчас выполняется. Обратите внимание, что комбинации ([2,1,0], 2) возвращают [(2, 1), (2, 0), (1, 0)]. После выполнения приведенного выше кода мы получим следующую ошибку: Из выходных данных становится ясно, что возвращающая num1/num2 строка является местом возникновения ошибки, но непонятно, какие значения num1 и num2 ее вызывают. Это можно легко отследить, добавив декоратор Loguru.catch: Вывод: Добавив logger.catch исключения гораздо проще понять: ошибка возникает при делении 2 на 0. Как быть, если в коде нет ошибки, но мы хотим выяснить, что в нем происходит? В этом случае пригодится snoop. Это пакет Python, который выводит на экран строки выполняемого кода вместе со значениями каждой переменной, добавляя только один декоратор. Чтобы установить snoop, введите следующую команду: Представим, что у нас есть функция под названием factorial, которая находит факториал целого числа: Вывод: Чтобы понять, почему результат factorial(5) равен 20, добавим декоратор snoop в функцию factorial. Вывод: В приведенном выше выводе можно просмотреть значения переменных, и какие строки кода выполняются. Теперь легче понять, как работает рекурсия. Если необходимо визуализировать, какие строки и сколько раз выполняются, попробуйте heartrate. Heartrate также создан разработчиками snoop. Чтобы его установить, введите команду: Теперь добавим heartrate.trace(browser=True) в предыдущий код. Это откроет отображающее визуализацию файла окно браузера, в котором была вызвана функция trace(): При запуске приведенного выше кода должен открыться новый браузер. Если нет, перейдите на http://localhost:9999 – вы должны увидеть показанный ниже результат: Диаграммы подсвечивают искомые строки: более длинные полосы означают больше попаданий, а светлые цвета – более свежее изменение. На приведенной выше иллюстрации мы видим, как выполняется код: Вывод имеет смысл, так как начальное значение x равно 5, и функция вызывается повторно до тех пор, пока x не станет равным 1. Теперь посмотрим, как визуализировать выполнение в режиме реального времени с помощью heartrate. Добавим sleep(0.5), чтобы программа работала немного медленнее, и увеличим num до 20. Теперь мы можем в режиме реального времени видеть, какие строки кода выполняются, и сколько раз отработала каждая из них. Мы изучили три инструмента для отслеживания и визуализации выполнения кода в Python. Надеемся, что с ними отладка станет для вас менее болезненной. Поскольку эти инструменты требуют только одной строки кода, почему бы не попробовать их в работе? Удачи в обучении! Дополнительные материалы:Мотивация
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
pip install loguru
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 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
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)
Snoop
pip install snoop
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
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
pip install heartrate
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)}")
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)}")
Заключение
- 6 views
- 0 Comment