Использование операторов печати только для отладки

110

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

сумасшедший
источник

Ответы:

162

В loggingмодуле есть все, что вам нужно. Сначала это может показаться чрезмерным, но используйте только те детали, которые вам нужны. Я бы рекомендовал использовать logging.basicConfigдля переключения уровня ведения журнала stderrи метод простого журнала , debug, info, warning, errorи critical.

import logging, sys
logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
logging.debug('A debug message!')
logging.info('We processed %d records', len(processed_records))
Мэтт Джойнер
источник
5
Также, если у вас возникли проблемы с установкой этого модуля, как у меня; ведение журнала является частью стандартной библиотеки - установка pip не требуется даже при использовании виртуальной среды
Амр
Как установить уровень ведения журнала, чтобы он только печатал ошибки, а не сообщения отладки?
Эдуардо Пиньятелли
@EduardoPignatelli levelв basicConfigвызове установил на logging.ERROR.
Мэтт Джойнер,
Боюсь, что это не работает на jupyter lab 1.2.6. Вы можете установить уровень ведения журнала один раз, и повторная настройка использования не logging.basicConfig(stream=sys.stderr, level=logging.ERROR)будет иметь никакого эффекта. Перезагрузка ядра и установка нового уровня работают, но для меня это обходной путь.
Эдуардо Пиньятелли,
@EduardoPignatelli, вам следует задать еще один вопрос. Но, вероятно, вам нужно будет напрямую изменить уровень в корневом регистраторе, jupyter, вероятно, вызывает basicConfig перед вами.
Мэтт Джойнер,
28

Простой способ сделать это - вызвать функцию регистрации:

DEBUG = True

def log(s):
    if DEBUG:
        print s

log("hello world")

Затем вы можете изменить значение DEBUGи запустить свой код с ведением журнала или без него.

Стандартный loggingмодуль имеет более сложный механизм для этого.

Грег Хьюгилл
источник
5
Вероятно, в долгосрочной перспективе лучше использовать прилагаемый модуль ведения журнала, чем использовать собственный (хотя это выглядит более сложным).
mgiuca 05
11
Верно, но стоит разобраться, как можно самостоятельно катить.
Грег Хьюгилл 05
1
На самом деле. Вышесказанное дает хорошее представление о том, как loggingработает (на очень простом уровне).
mgiuca 05
Это тот, который я использую для своих лямбд aws.
crsuarezf 07
21

Используйте модуль встроенной библиотеки журналирования вместо печати.

Вы создаете Loggerобъект (скажем logger), а затем после этого, когда вы вставляете отладочную печать, вы просто помещаете:

logger.debug("Some string")

Вы можете использовать logger.setLevelв начале программы, чтобы установить выходной уровень. Если вы установите его в DEBUG, он распечатает все отладки. Установите его в INFO или выше, и сразу все отладки исчезнут.

Вы также можете использовать его для регистрации более серьезных вещей на разных уровнях (ИНФОРМАЦИЯ, ПРЕДУПРЕЖДЕНИЕ и ОШИБКА).

mgiuca
источник
12

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

logging.debug("datastructure: %r" % complex_dict_structure)

убедитесь, что вы делаете:

logging.debug("datastructure: %r", complex_dict_structure)

потому что, хотя они выглядят одинаково, первая версия требует затрат на repr (), даже если она отключена . Вторая версия избегает этого. Точно так же, если вы катаетесь самостоятельно, я бы предложил что-то вроде:

def debug_stdout(sfunc):
    print(sfunc())

debug = debug_stdout

Вызывается через:

debug(lambda: "datastructure: %r" % complex_dict_structure)

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

def debug_noop(*args, **kwargs):
    pass

debug = debug_noop

Накладные расходы на вычисление этих строк, вероятно, не имеют значения, если только они 1) не дороги в вычислении или 2) оператор отладки находится в середине, скажем, цикла n ^ 3 или чего-то еще. Не то чтобы я что-нибудь об этом знал.

pjz
источник
Дополнительная информация по этой важной теме в разделе «Оптимизация» в руководстве по ведению
Мартин CR
7

Не знаю, как другие, но меня использовали для определения «глобальной константы» ( DEBUG), а затем глобальной функции ( debug(msg)), которая будет печатать, msgтолько если DEBUG == True.

Затем я пишу свои отладочные операторы, например:

debug('My value: %d' % value)

... затем я беру модульное тестирование и больше никогда этого не делал! :)

Mac
источник
Модульное тестирование ха. Ладно, тогда это еще одна вещь, которую нужно поднять :(
crazyaboutliv
1
Я не хочу препятствовать модульному тестированию - это очень важно. Но я не думаю, что это замена журналированию, даже как способ отладки. Я все еще много печатаю, чтобы быстро что-то проверить.
mgiuca 05
@crazyaboutliv - Модульное тестирование выполнено правильно. Взгляните на эту главу о погружении в Python, чтобы получить быструю, лаконичную и понятную презентацию
Mac
@mgiuca - Я тоже быстро распечатываю, но это всего лишь пара или около того, print()пока мой код доведен до необходимого уровня для прохождения теста. Я никогда не получаю огромное количество print()всего. Ведение журнала тоже круто! :)
mac
2
@mac Похоже, ваша ссылка теперь требует явного www - теперь она размещена здесь .
Culix