Отладка кода на Python с помощью icecream

Вопрос: какую из стандартных функций Python разработчики используют чаще всего? Наверняка, как и в большинстве языков программирования, ответом будет функция print(): во время разработки трудно удержаться от многократного вывода сообщений в консоль.

Конечно, не существует альтернативы, способной полностью заменить функцию print(). Однако для вывода отладочных сообщений в консоль лучше использовать другие инструменты. Например, в статье представлена интересная сторонняя библиотека Python под названием “IceCream”: с её помощью вы откроете для себя множество удобств быстрой и простой отладки программного кода.

Плохой пример

JavaMentor
JavaMentor

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

def square_of(num):
    return num*num

Вышеописанная функция банально возвращает квадрат числа, переданного в качестве аргумента. Проверим её пару раз: 

print(square_of(2))
print(square_of(3))
print(square_of(4))

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

print('square of 2:', square_of(2))
print('square of 3:', square_of(3))
print('square of 4:', square_of(4))

Теперь пример стал немного лучше, но каждый раз вручную прописывать пояснительные строки  —  слишком утомительно. Более того, после окончания разработки, скорее всего, вам придется удалить почти все отладочные сообщения.

Проверка переменных

Обратим внимание на Python-библиотеку под названием “Ice Cream” и ответим на вопрос: как она решает проблемы, о которых говорилось выше?

Прежде всего, необходимо установить библиотеку из репозитория PyPI с помощью пакетного менеджера pip (или любого другого):

pip install icecream

Перед использованием библиотеки  —  импортируем её в программу:

from icecream import ic

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

Вызов функции

Библиотеку icecream можно использовать напрямую для вывода возвращаемых функцией значений в консоль, точно так же, как ранее использовалась функция print().

ic(square_of(2))
ic(square_of(3))
ic(square_of(4))

Отлично! Несмотря на то, что не указано ни одного отладочного сообщения для вызова функции ic(), она все равно выводит на экран имя функции, ее аргументы и результат выполнения. Таким образом, нам больше не нужно вручную добавлять “краткое описание”.

Доступ к словарю

Кроме обычного вызова функции, похожего на print(), библиотека icecream способна выводить всю необходимую информацию в удобном для чтения виде, ускоряя и облегчая отладку, например при обращении к паре ключ-значение в словаре.

my_dict = {
    'name': 'Chris',
    'age': 33
}

ic(my_dict['name'])

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

Доступ к атрибутам объекта

В качестве еще одного примера, давайте определим класс и создадим для него объект-экземпляр:

class Dog():
    num_legs = 4
    tail = True

dog = Dog()

Вывод в консоль значения атрибута объекта-экземпляра класса Dog с помощью библиотеки icecream:

ic(dog.tail)

Отладка условия if

Библиотека icecream упрощает проверку не только переменных, но и управляющих конструкций, таких как условие if. Например, рассмотрим простое условие:

input = 'Chris'

if input == 'Chris':
    ic()
else:
    ic()

Для начала разместим вызов функции icecream в блоках if и else. Посмотрим, что произойдет:

Хотя в коде программы оператор условия if-else буквально ничего не делает, функция ic() выводит в консоль номер строки, где она была вызвана, и время вызова.

Пример демонстрируется в Jupyter Notebook, но при запуске функции ic() из файла в формате .py, кроме номера строки и времени запуска вы также получите имя файла, из которого произошел вызов.

Рассмотрим более практичный случай использования функции ic() из Python-библиотеки icecream:

def check_user(username):
    if username == 'Chris':
        # Делается что-либо
        ic()
    else:
        # Делается что-либо еще
        ic()

check_user('Chris')
check_user('Jade')

При вызове функция check_user() подействует в зависимости от значения аргумента username. Допустим, в целях отладки важно знать, кто именно является текущим пользователем. Функция ic() как раз сообщает нам это:

Вставка в существующий код

Далее обсудим одну интересную особенность библиотеки icecream: функция ic() не только выводит подробную информацию в консоль, но и передает значение таким образом, что оно может использоваться в качестве функции-обертки для всего что угодно. Другими словами, функция ic() способна обернуть в себя любой объект, не затрагивая создавая последствий.

Давайте рассмотрим новый функционал библиотеки icecream на примере все той же функции sqaure_of(), определенной в предыдущем разделе статьи.

num = 2

square_of_num = square_of(ic(num))

В примере определена переменная num, и нам нужно вычислить ее квадрат с помощью вызова функции square_of(). Вместо square_of(num) в примере выше функция ic() оборачивает саму переменную num. Таким образом, консольный вывод будет состоять не из результата работы функции square_of(num), присвоенного переменной square_of_num, а только из значения самой переменной num.

А вот протестировать результат из переменной square_of_num можно следующим образом:

Как видно, square_of_num равна квадрату переменной num. Кроме того, в данном if-условии не только функция ic() используется без влияния на результат, но и переменная square_of_num все равно выводится для отладки!

Отключение библиотеки icecream

Одна из больших проблем использования функции print() в отладочных целях заключается в том, что сообщений слишком много. Кроме того, они часто остаются повсюду после завершения разработки. В таком случае желание быстро очистить код от отладочных сообщений, написанных с помощью функции print(), приведет к настоящей катастрофе.

А вот в случае использования отладочной библиотеки icecream, все, что нам нужно сделать,  —  это просто отключить ее!

ic.disable()

После выполнения метода ic.disable() все функции ic(), из любого места в коде программы, перестанут что-либо выводить в консоль. Например, приведенный ниже код ничего не выведет:

Тем не менее следует задаться вопросом: как насчет переменной square_of_num? Будет ли она по-прежнему передаваться после отключения библиотеки icecream? Не волнуйтесь, ic.disable() отключает исключительно вывод текста в консоль, не нужно беспокоиться о работоспособности обернутых в ic() функций.

if ic(square_of_num) == pow(num, 2):
    print('Correct!')

При замене консольного вывода обратно на функцию print(), программа все равно будет работать. Получается, что ic(square_of_num) по-прежнему эквивалентно square_of_num:

Конечно, снова понадобится вернуться в режим отладки, icecream очень легко включается обратно:

ic.enable()

Настройка отладочных сообщений

Библиотека icecream реализовывает тонкую настройку и форматирование сообщений. Самой популярной настройкой считается изменение префикса. Вы, наверное, заметили, что вывод отладочных сообщений по умолчанию всегда начинается с префикса ic |. Это можно изменить.

Например, ввиду отладочной цели хорошей идеей будет указать слово Debug в качестве префикса:

ic.configureOutput(prefix='Debug | ')
ic('test')

Более того, в качестве префикса можно указывать не только статические строки, но и функции. Например, определим функцию, возвращаемое значение которой является текущей временной меткой в виде форматированной строки.

from datetime import datetime

def now():
    return f'[{datetime.now()}] '

Затем установим полученную функцию now() в качестве префикса отладочных сообщений icecream:

ic.configureOutput(prefix=now)
ic('test')

Выводы

В статье представлена замечательная сторонняя Python-библиотека под названием “Ice Cream”. Она улучшает функцию print(), детализируя ее и повышая удобство отладки программ на Python.

Библиотека icecream никогда не заменит стандартную функцию print(), потому что у них разные цели, а также систему протоколирования. Она скорее находится где-то между этими двумя инструментами. 

Жизнь коротка, используйте Python!

Читайте также:

Читайте нас в Telegram, VK и Яндекс.Дзен


Перевод статьи Christopher Tao: Do Not Use Print For Debugging In Python Anymore

Предыдущая статьяАвтоматический анализ текста с использованием Streamlit