Używanie instrukcji print tylko do debugowania

109

Ostatnio dużo programowałem w Pythonie. Pracowałem z danymi, z którymi wcześniej nie pracowałem, używając formuł, których nigdy wcześniej nie widziałem i radziłem sobie z ogromnymi plikami. Wszystko to sprawiło, że napisałem wiele drukowanych oświadczeń, aby sprawdzić, czy wszystko idzie dobrze i zidentyfikować punkty awarii. Ale generalnie generowanie tak dużej ilości informacji nie jest dobrą praktyką. Jak używać instrukcji print tylko wtedy, gdy chcę debugować i pozwolić na ich pomijanie, gdy nie chcę, aby były drukowane?

crazyaboutliv
źródło

Odpowiedzi:

161

loggingModuł posiada wszystko, co chcesz. Na początku może się to wydawać przesadne, ale używaj tylko tych części, których potrzebujesz. Polecam za pomocą logging.basicConfig, aby przełączyć poziom rejestrowania do stderri metody dziennika prosty , debug, info, warning, errori 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))
Matt Joiner
źródło
5
Również w przypadku problemów z instalacją tego modułu, tak jak ja; logowanie jest częścią standardowej biblioteki - nie ma potrzeby instalacji pip nawet w środowisku wirtualnym
Amr
Jak ustawić poziom rejestrowania tak, aby wyświetlał tylko błędy, a nie komunikaty debugowania?
Eduardo Pignatelli
@EduardoPignatelli ustawił levelw basicConfigwywołaniu na logging.ERROR.
Matt Joiner
Obawiam się, że to nie działa w jupyter lab 1.2.6. Możesz ustawić poziom rejestrowania raz, a ponowne ustawienie używania nie logging.basicConfig(stream=sys.stderr, level=logging.ERROR)przyniesie żadnego efektu. Ponowne uruchomienie jądra i ustawienie nowego poziomu działa, ale to dla mnie obejście.
Eduardo Pignatelli
@EduardoPignatelli powinieneś zadać w tej sprawie kolejne pytanie. Ale prawdopodobnie będziesz musiał bezpośrednio zmienić poziom w głównym programie rejestrującym, jupyter prawdopodobnie wywołuje przed tobą basicConfig.
Matt Joiner
28

Prostym sposobem na to jest wywołanie funkcji rejestrowania:

DEBUG = True

def log(s):
    if DEBUG:
        print s

log("hello world")

Następnie możesz zmienić wartość DEBUGi uruchomić kod z rejestrowaniem lub bez.

Standardowy loggingmoduł ma do tego bardziej rozbudowany mechanizm.

Greg Hewgill
źródło
5
Prawdopodobnie na dłuższą metę lepiej jest użyć dostarczonego modułu logowania niż utworzyć własny (nawet jeśli wygląda to na bardziej skomplikowane).
mgiuca
11
To prawda, ale warto zrozumieć, jak można toczyć własne.
Greg Hewgill,
1
W rzeczy samej. Powyższe jest dobrym pomysłem na to, jak loggingdziała (na bardzo prostym poziomie).
mgiuca
To jest ten, którego używam w moich lambdach AWS.
crsuarezf
21

Zamiast drukowania użyj wbudowanego modułu biblioteki rejestrowania .

Tworzysz Loggerobiekt (powiedzmy logger), a następnie, za każdym razem, gdy wstawiasz wydruk debugowania, po prostu wstawiasz:

logger.debug("Some string")

Możesz użyć logger.setLevelna początku programu, aby ustawić poziom wyjściowy. Jeśli ustawisz ją na DEBUG, wypisze wszystkie błędy. Ustaw go na INFO lub wyższą, a wszystkie błędy natychmiast znikną.

Możesz go również użyć do rejestrowania poważniejszych rzeczy na różnych poziomach (INFO, WARNING i ERROR).

mgiuca
źródło
12

Po pierwsze, poproszę o nominację platformy logowania Pythona . Uważaj jednak, jak go używasz. W szczególności: pozwól platformie rejestrowania rozszerzyć twoje zmienne, nie rób tego sam. Na przykład zamiast:

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

upewnij się, że:

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

ponieważ chociaż wyglądają podobnie, pierwsza wersja ponosi koszt repr (), nawet jeśli jest wyłączona . Druga wersja tego uniknąć. Podobnie, jeśli zrobisz własne, zasugeruję coś takiego:

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

debug = debug_stdout

zadzwonił przez:

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

co znowu pozwoli uniknąć narzutów, jeśli wyłączysz go, wykonując:

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

debug = debug_noop

Narzut obliczania tych ciągów prawdopodobnie nie ma znaczenia, chyba że są one albo 1) drogie do obliczenia, albo 2) instrukcja debugowania znajduje się w środku, powiedzmy, pętli n ^ 3 lub czegoś takiego. Nie to, żebym coś o tym wiedział.

pjz
źródło
Więcej informacji na ten ważny temat znajduje się w sekcji „optymalizacja” w opisie logowania: poradniku docs.python.org/3/howto/logging.html#optimization
Martin CR
7

Nie wiem o innych, ale byłem używany do zdefiniowania „stałej globalnej” ( DEBUG), a następnie funkcji globalnej ( debug(msg)), która wyświetlałaby się msgtylko wtedy, gdy DEBUG == True.

Następnie piszę instrukcje debugowania, takie jak:

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

... potem przechodzę testy jednostkowe i nigdy więcej tego nie zrobiłem! :)

prochowiec
źródło
Badania jednostkowe ha. Okay, to kolejna rzecz do odebrania :(
crazyaboutliv
1
Nie chcę zniechęcać do testów jednostkowych - to jest niezbędne. Ale nie sądzę, żeby to substytut rejestrowania, nawet jako technika debugowania. Nadal dużo drukuję, aby szybko przetestować.
mgiuca
@crazyaboutliv - Prawidłowo wykonane testy jednostkowe są świetne. Rzuć okiem na ten rozdział poświęcony pythonowi, aby uzyskać zwięzłą, łatwą do zrozumienia prezentację
mac,
@mgiuca - ja też robię szybkie drukowanie, ale to tylko kilka lub kilka razy, zanim print()mój kod zostanie podniesiony do wymaganego poziomu, aby zdać test. Nigdy nie kończę z ogromną ilością w print()każdym miejscu. Rejestrowanie też jest fajne! :)
mac
2
@mac Wygląda na to, że twój link wymaga teraz jawnego „www” - jest teraz hostowany tutaj .
culix