В самом начале работы над новым проектом или создании его прототипа, вряд ли кто сразу бросается настраивать модуль logging
для отладки кода или инспектировании переменных. 85% разработчиков используют для этих целей функцию print()
.
Делать отладку немного приятнее, используя сторонний модуль icecream
, или сокращенно ic
. Этот модуль похож на функцию print()
, но лучше и не требует специальной настройки, подобной модулю logging
.
ВНИМАНИЕ: Модуль icecream
НЕ работает в терминале Python и в случае попытки выполнить icecream.ic()
будет ругаться, что не удалось получить доступ к базовому исходному коду для анализа. Не запускайте примеры в терминале, они будут работать, если запускать файл с кодом представленных ниже примеров.
Краткая характеристика модуля icecream
:
print()
;icecream
в виртуальное окружение:# создаем виртуальное окружение, если нет $ python3 -m venv .venv --prompt VirtualEnv # активируем виртуальное окружение $ source .venv/bin/activate # ставим модуль icecream (VirtualEnv):~$ python -m pip install -U icecream
icecream
.icecream
.icecream
из импортируемых файлов.icecream
.При отладке программы иногда необходимо вывести значения некоторых переменных или выражений, при этом функцию print()
используют следующим образом:
print(foo('123')) # или print("foo('123')", foo('123'))
В данной ситуации очень поможет функцию ic()
модуля icecream
. С помощью аргументов, ic()
проверяет себя и выводит как свои собственные аргументы, так и значения этих аргументов.
from icecream import ic def foo(i): return i + 333 ic(foo(123)) # ic| foo(123): 456 ic(foo(123), 1 + 5); # ic| foo(123): 456, 1 + 5: 6 # типы данных d = {'key': {1: 'one'}} ic(d['key'][1]) # ic| d['key'][1]: 'one' # структуры class klass(): attr = 'yep' ic(klass.attr) # ic| klass.attr: 'yep'
Для определения, какие части программы и в каком порядке выполняются, необходимо укать функцию ic()
, в нужных частях кода, без аргументов. В этом случае она проверит сама себя и напечатает вызывающее имя файла, номер строки и родительскую функцию.
from icecream import ic def foo(): ic() first() if expression: ic() second() else: ic() third() # ic| test.py:4 in foo() # ic| test.py:11 in foo()
icecream
.Функция ic()
возвращает переданные ей аргументы, следовательно ее можно легко вставить в уже существующий код.
from icecream import ic a = 6 def half(i): return i / 2 b = half(ic(a)) # ic| a: 6 ic(b) # ic| b: 3
Команда ic.format(*args)
похож на ic()
, но вывод возвращается в виде строки, а не записывается в stderr
.
from icecream import ic s = 'sup' out = ic.format(s) print(out) # ic| s: 'sup'
icecream
.Вывод функции ic()
можно полностью отключить, а позже снова включить с помощью ic.disable()
и ic.enable()
соответственно. При отключенном выводе, функция ic()
, конечно же, продолжит возвращать переданные ей аргументы.
from icecream import ic ic(1) ic.disable() ic(2) ic.enable() ic(3) # ic| 1: 1 # ic| 3: 3
icecream
из импортируемых файлов.Чтобы сделать ic()
доступным в каждом файле программы без необходимости импорта его в каждый файл, то нужно вызвать функцию install()
в корневом файле. Например:
# запускаемый файл `a.py` from icecream import install install() from B import foo foo()
А затем в файле b.py
, который импортируется в a.py
, просто будем вызывать функцию ic()
:
# импортируемый файл `b.py` def foo(): x = 3 ic(x)
Функция install()
добавляет ic()
во встроенный модуль builtins
, который используется всеми файлами, импортированными интерпретатором. Точно так же ic()
позже можно удалить функцией uninstall()
.
Функция ic()
также может быть импортирована способом, который не завершается сбоем, если модуль icecream
не установлен, например, на боевых серверах. С этой целью можно использовать следующий фрагмент импорта:
try: from icecream import ic except ImportError: # откат, если модуль `icecream` не установлен. ic = lambda *a: None if not a else (a[0] if len(a) == 1 else a)
icecream
.Для настройки вывода icecream
можно использовать ic.configureOutput()
. Вот ее синтаксис:
ic.configureOutput(prefix='ic |', outputFunction=sys.stderr, argToStringFunction=pprint.pformat, includeContext=False)
Она поможет изменить следующие настройки по умолчанию:
ic |
), sys.stderr
), ic()
(имя файла, номер строки и родительскую функцию) в ее вывод.prefix
.Аргумент prefix
отвечает за изменение префикса, при выводе отладочной информации.
from icecream import ic ic.configureOutput(prefix='hello => ') ic('world') # hello => 'world'
Значение аргумента prefix
также может быть функцией.
import time from icecream import ic def unixTimestamp(): return f'{int(time.time())} |' ic.configureOutput(prefix=unixTimestamp) ic('world') 1519185860 | 'world': 'world'
outputFunction
.Аргумент outputFunction
, должен быть функцией, в которую будет передан вывод ic()
. По умолчанию используется sys.stderr
.
import logging from icecream import ic def warn(s): logging.warning(s) ic.configureOutput(outputFunction=warn) ic('eep') # WARNING:root:ic| 'eep': 'eep'
argToStringFunction
.Аргумент outputFunction
, должен быть функцией, которая будет вызвана со значениями аргументов, передаваемых ic()
и которые должны быть сериализованы в отображаемые строки. По умолчанию используется функция pprint.pformat()
, но ее можно изменить, например, для обработки нестандартных типов данных индивидуальным образом.
from icecream import ic def toString(obj): if isinstance(obj, str): return f'[!string "{obj}" with length {len(obj)}!]' return repr(obj) ic.configureOutput(argToStringFunction=toString) ic(7, 'hello') # ic| 7, [!string "hello" with length 5!]
includeContext
.Если аргумент IncludeContext=True
, то в вывод добавляется: имя файла, родительская функция и номер строки, в которой вызвана ic()
.
from icecream import ic ic.configureOutput(includeContext=True) def foo(): ic('str') foo() # ic| test.py:5 in foo()- 'str'