3 инструмента для отслеживания и визуализации выполнения вашего кода 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

Наверняка вам бы хотелось, чтобы вывод ошибки был более информативный, как на скриншоте ниже:


Так же возможно визуализировать, те строки кода,которые выполняются в реальном времени:
Итак, эта статья предоставит вам инструменты, чтобы сделать именно то, что описано выше. Вот эти 3 инструмента:

Loguru - выводит  исключения в коде
snoop - напечатает строки кода, выполняемого в функции
Heartrate - визуализирует выполнение программы Python в режиме реального времени
И все, что нужно для использования этих инструментов, - в одну строчка кода!

Loguru — Print Better Exceptions

Loguru - это библиотека, цель которой - сделает вывод в Python приятным занятием. Loguru предоставляет множество интересных функций, но одна из функций, которые я считаю наиболее полезными, - это способность обнаруживать неожиданные ошибки и отображать их.

Чтобы установить Loguru, введите команду

pip install loguru
Чтобы понять, чем может быть полезен Loguru, представьте, что у вас есть 2 функции: div и div_numbers, и выполняется функция div_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)]. После выполнения приведенного выше кода мы получаем эту ошибку:
<!-- wp:preformatted -->
<pre id="tw-target-text" class="wp-block-preformatted">Обратите внимание, что комбинации ([2,1,0], 2) возвращают [(2, 1), (2, 0), (1, 0)]. После выполнения приведенного выше кода мы получаем эту ошибку:



</pre>
<!-- /wp:preformatted -->
Из выходных данных мы знаем, что ошибка возникает в строке, возвращающей num1 / num2, но мы не знаем, какие значения num1 и num2 вызывают ошибку. К счастью, это можно легко отследить, добавив декоратор Loguru logger.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 — Print the Lines of Code being Executed in a Function

Что делать, если в коде нет ошибки, но мы хотим выяснить, как проходит выполнение код? Вот тут-то и пригодится 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 - Визуализация выполнения программы Python в режиме реального времени
 
Если вы хотите визуализировать, какие строки выполняются и сколько раз они выполняются, попробуйте сердечный ритм.

 Чтобы установить либу, введите:
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. Вы должны увидеть результат, как показано ниже:
Из вывода выше мы видим, что программа выполняется следующим образом:

если x == 1 5 раз
вернуть 1 раз
return (x * factorial (x-1)) 4 раза
Вывод имеет смысл, поскольку начальное значение x равно 5, и функция вызывается повторно, пока x не станет равным 1.

Теперь давайте посмотрим - визуализации выполнение программы Python в реальном времени с использованием heartrate. Давайте добавим sleep (0,5), чтобы программа работала немного медленнее, и увеличим число до 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)}")
Мы можем видеть, какие строки кода выполняются и сколько раз выполнялась каждая из них в режиме реального времени.

Ответить