Utilizzo di istruzioni print solo per eseguire il debug


109

Negli ultimi tempi ho scritto molto in Python. E ho lavorato con dati su cui non avevo mai lavorato prima, utilizzando formule mai viste prima e gestendo file enormi. Tutto ciò mi ha fatto scrivere molte dichiarazioni di stampa per verificare se tutto va bene e identificare i punti di errore. Ma, in generale, fornire così tante informazioni non è una buona pratica. Come posso utilizzare le istruzioni print solo quando voglio eseguire il debug e lasciarle ignorare quando non voglio che vengano stampate?

Risposte:


161

Il loggingmodulo ha tutto ciò che potresti desiderare. All'inizio può sembrare eccessivo, ma usa solo le parti di cui hai bisogno. Mi consiglia di utilizzare logging.basicConfigper attivare o disattivare il livello di registrazione stderrei metodi di registro semplice , debug, info, warning, errore 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
Inoltre, nel caso avessi problemi a installare questo modulo come me; la registrazione fa parte della libreria standard - non è necessaria l'installazione di pip anche quando si utilizza un ambiente virtuale
Amr

Come si imposta il livello di registrazione in modo tale da stampare solo gli errori e non i messaggi di debug?
Eduardo Pignatelli

@EduardoPignatelli impostato level, nella basicConfigchiamata, a logging.ERROR.
Matt Joiner

Temo che questo non funzioni su jupyter lab 1.2.6. È possibile impostare il livello di registrazione una volta e la reimpostazione in uso logging.basicConfig(stream=sys.stderr, level=logging.ERROR)non avrà alcun effetto. Riavviare il kernel e impostare il nuovo livello funziona, ma per me è una soluzione alternativa.
Eduardo Pignatelli

@EduardoPignatelli dovresti fare un'altra domanda per questo. Ma probabilmente dovrai cambiare direttamente il livello sul logger di root, probabilmente jupyter sta chiamando basicConfig prima di te.
Matt Joiner

28

Un modo semplice per farlo è chiamare una funzione di registrazione:

DEBUG = True

def log(s):
    if DEBUG:
        print s

log("hello world")

Quindi puoi modificare il valore di DEBUGed eseguire il codice con o senza registrazione.

Il loggingmodulo standard ha un meccanismo più elaborato per questo.


5
Probabilmente è meglio a lungo termine utilizzare il modulo di registrazione fornito piuttosto che eseguire il proprio (anche se sembra più complicato).
mgiuca

11
Vero, ma vale la pena capire come si potrebbe rotolare da soli.
Greg Hewgill

1
Infatti. Quanto sopra è una buona idea di come loggingfunziona (a un livello molto semplice).
mgiuca

Questo è quello che uso per i miei aws lambdas.
crsuarezf

21

Utilizzare la registrazione modulo incorporato libreria al posto della stampa.

Crei un Loggeroggetto (diciamo logger) e poi, ogni volta che inserisci una stampa di debug, metti semplicemente:

logger.debug("Some string")

È possibile utilizzare logger.setLevelall'inizio del programma per impostare il livello di uscita. Se lo imposti su DEBUG, stamperà tutti i debug. Impostalo su INFO o superiore e immediatamente tutti i debug scompariranno.

Puoi anche usarlo per registrare cose più serie, a diversi livelli (INFO, ATTENZIONE ed ERRORE).


12

Prima di tutto, seguirò la nomina del framework di registrazione di Python . Tuttavia, fai un po 'attenzione a come lo usi. Nello specifico: lascia che il framework di registrazione espanda le tue variabili, non farlo da solo. Ad esempio, invece di:

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

assicurati di fare:

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

perché mentre sembrano simili, la prima versione sostiene il costo di repr () anche se è disabilitata . La seconda versione lo evita. Allo stesso modo, se fai il tuo, suggerirei qualcosa del tipo:

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

debug = debug_stdout

chiamato tramite:

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

che, ancora una volta, eviterà l'overhead se lo disabiliti facendo:

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

debug = debug_noop

Il sovraccarico del calcolo di quelle stringhe probabilmente non ha importanza a meno che non siano 1) costosi da calcolare o 2) l'istruzione di debug sia nel mezzo, diciamo, di un ciclo n ^ 3 o qualcosa del genere. Non che ne sapessi nulla.


Ci sono ulteriori informazioni su questo importante argomento in "ottimizzazione" nella procedura di registrazione: docs.python.org/3/howto/logging.html#optimization
Martin CR,

7

Non conosco altri, ma ero abituato a definire una "costante globale" ( DEBUG) e quindi una funzione globale ( debug(msg)) che sarebbe stampata msgsolo se DEBUG == True.

Quindi scrivo le mie dichiarazioni di debug come:

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

... poi riprendo i test unitari e non l'ho più fatto! :)


Test unitario ha. Ok, questa è un'altra cosa da raccogliere allora :(
crazyaboutliv

1
Non voglio scoraggiare i test unitari: è essenziale. Ma non penso che sia un sostituto per la registrazione, anche come tecnica di debug. Faccio ancora molte stampe per testare rapidamente le cose.
mgiuca

@crazyaboutliv - I test di unità eseguiti correttamente sono fantastici. Dai un'occhiata a questo capitolo sull'immersione in Python per una presentazione scattante, concisa e facile da seguire
mac

@mgiuca - Faccio anche la stampa veloce, ma è solo un paio di volte print()mentre alzo il mio codice al livello richiesto per superare il test. Non mi ritrovo mai con una quantità enorme di print()tutto il posto. Anche la registrazione è fantastica! :)
mac

2
@mac Sembra che il tuo link ora richieda un "www" esplicito - ora è ospitato qui .
culix
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.