Використання операторів друку лише для налагодження


109

Я багато пізніше кодував у Python. І я працював з даними, з якими раніше не працював, використовуючи формули, які ніколи не бачив, і маю справу з величезними файлами. Все це змусило мене написати багато друкованих заяв, щоб перевірити, чи все в порядку, і визначити моменти відмови. Але, як правило, виведення такої кількості інформації не є хорошою практикою. Як я можу використовувати оператори друку лише тоді, коли я хочу налагоджувати помилки, і пропускати їх, коли я не хочу їх друкувати?

Відповіді:


161

У 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
Також, якщо у вас виникли проблеми з установкою такого модуля, як я; ведення журналів є частиною стандартної бібліотеки - немає необхідності встановлювати протокол навіть при використанні віртуального середовища
Amr

Як можна встановити рівень журналу таким чином, щоб він друкував лише помилки, а не налагоджував повідомлення?
Едуардо Піньятеллі

@EduardoPignatelli встановив level, у basicConfigвиклику, на logging.ERROR.
Метт Столяр

Боюся, це не працює в лабораторії юпітерів 1.2.6. Ви можете встановити рівень реєстрації один раз, і повторне налаштування з використанням logging.basicConfig(stream=sys.stderr, level=logging.ERROR)не матиме ефекту. Перезапуск ядра та встановлення нового рівня працює, але це для мене вирішення.
Едуардо Піньятеллі

@EduardoPignatelli вам слід задати ще одне запитання щодо цього. Але, ймовірно, вам знадобиться безпосередньо змінити рівень у кореневому журналі, юпітер, ймовірно, дзвонить basicConfig перед вами.
Метт Столяр

28

Простий спосіб зробити це - викликати функцію реєстрації даних:

DEBUG = True

def log(s):
    if DEBUG:
        print s

log("hello world")

Тоді ви можете змінити значення DEBUGта запустити свій код із або без реєстрації.

Стандартний loggingмодуль має для цього більш досконалий механізм.


5
Напевно, в довгостроковій перспективі краще використовувати наданий модуль ведення журналів, ніж прокручувати свій власний (навіть якщо це виглядає складніше).
mgiuca

11
Щоправда, але варто зрозуміти, як можна було прокати собі.
Грег Хьюгілл

1
Справді. Сказане - це гарна ідея того, як loggingпрацює (на дуже простому рівні).
mgiuca

Це те, що я використовую для своїх айв лямбда.
crsuarezf

21

Використовуйте вбудований модуль бібліотеки журналів замість друку.

Ви створюєте Loggerоб'єкт (скажімо logger), а потім після цього, щоразу, коли вставляєте друк налагодження, просто кладете:

logger.debug("Some string")

Ви можете використовувати logger.setLevelна початку програми для встановлення рівня виходу. Якщо встановити його на DEBUG, він надрукує всі налагодження. Встановіть його на INFO або вище, і відразу всі налагодження зникнуть.

Ви також можете використовувати його для реєстрації більш серйозних речей на різних рівнях (ІНФОРМАЦІЯ, ПОПЕРЕДЖЕННЯ та ПОМИЛКА).


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 циклу чи чогось іншого. Не те, щоб я щось про це знав.


Докладніші відомості щодо цієї важливої ​​теми в розділі "оптимізація" є в ході реєстрації: docs.python.org/3/howto/logging.html#optimization
Martin CR

7

Я не знаю про інших, але мене використовували для визначення "глобальної константи" ( DEBUG), а потім глобальної функції ( debug(msg)), яка друкувала б msgлише якщо DEBUG == True.

Тоді я пишу свої заяви про налагодження на зразок:

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

... тоді я підбираю тестування блоку і більше ніколи цього не робив! :)


Одиничне випробування га. Гаразд, це інша річ, яку потрібно забрати тоді :(
crazyaboutliv

1
Я не хочу перешкоджати тестуванню блоків - це дуже важливо. Але я не думаю, що це заміна для ведення журналів, навіть як техніка налагодження. Я все ще роблю багато друку, щоб швидко перевірити речі.
mgiuca

@crazyaboutliv - Тестування блоку, зроблене належним чином, чудово. Погляньте на цю главу занурення в пітон для швидкої, стислої та зручної презентації
mac

@mgiuca - Я також швидко друкую, але це лише пара або близько того print()часу, піднімаючи код до необхідного рівня, щоб пройти тест. Я ніколи не закінчуюсь величезною кількістю print()всього місця. Журнал теж класний! :)
mac

2
@mac Схоже, для вашого посилання зараз потрібен явний "www" - він розміщений тут .
culix
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.