Verwenden Sie print-Anweisungen nur zum Debuggen

109

Ich habe in letzter Zeit viel in Python programmiert. Und ich habe mit Daten gearbeitet, mit denen ich noch nie gearbeitet habe, mit noch nie dagewesenen Formeln und mit riesigen Dateien. All dies hat mich dazu gebracht, viele Druckanweisungen zu schreiben, um zu überprüfen, ob alles richtig läuft, und um die Fehlerquellen zu identifizieren. Im Allgemeinen ist es jedoch keine gute Praxis, so viele Informationen auszugeben. Wie verwende ich die print-Anweisungen nur, wenn ich debuggen möchte, und lasse sie überspringen, wenn ich nicht möchte, dass sie gedruckt werden?

crazyaboutliv
quelle

Antworten:

161

Das loggingModul bietet alles, was Sie sich wünschen können. Es mag zunächst übertrieben erscheinen, aber verwenden Sie nur die Teile, die Sie benötigen. Ich würde empfehlen , mit logging.basicConfigder Protokollebene auf wechseln stderrund die einfachen Log - Methoden , debug, info, warning, errorund 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
quelle
5
Falls Sie Probleme bei der Installation dieses Moduls wie ich hatten; Die Protokollierung ist Teil der Standardbibliothek - keine Pip-Installation erforderlich, selbst wenn eine virtuelle Umgebung verwendet wird
Amr
Wie stellt man die Protokollierungsstufe so ein, dass nur Fehler gedruckt und keine Nachrichten debuggt werden?
Eduardo Pignatelli
@EduardoPignatelli stellte levelim basicConfigAnruf auf logging.ERROR.
Matt Joiner
Ich fürchte, dies funktioniert nicht im Jupyter Lab 1.2.6. Sie können die Protokollierungsstufe einmal einstellen, und die erneute Einstellung logging.basicConfig(stream=sys.stderr, level=logging.ERROR)hat keine Auswirkung. Das Neustarten des Kernels und das Festlegen der neuen Ebene funktioniert, aber das ist eine Problemumgehung für mich.
Eduardo Pignatelli
@EduardoPignatelli du solltest dafür eine andere Frage stellen. Aber wahrscheinlich müssen Sie die Ebene im Root-Logger direkt ändern. Jupiter ruft wahrscheinlich basicConfig vor Ihnen auf.
Matt Joiner
28

Eine einfache Möglichkeit, dies zu tun, besteht darin, eine Protokollierungsfunktion aufzurufen:

DEBUG = True

def log(s):
    if DEBUG:
        print s

log("hello world")

Anschließend können Sie den Wert von ändern DEBUGund Ihren Code mit oder ohne Protokollierung ausführen.

Das Standardmodul loggingverfügt hierfür über einen ausgefeilteren Mechanismus.

Greg Hewgill
quelle
5
Auf lange Sicht ist es wahrscheinlich besser, das mitgelieferte Protokollierungsmodul zu verwenden, als das eigene zu rollen (obwohl es komplizierter aussieht).
mgiuca
11
Das stimmt, aber es lohnt sich , zu verstehen , wie man könnte ihre eigene Rolle.
Greg Hewgill
1
Tatsächlich. Das Obige ist eine gute Vorstellung davon, wie es loggingfunktioniert (auf einer sehr einfachen Ebene).
mgiuca
Dies ist die, die ich für meine aws Lambdas benutze.
Crsuarezf
21

Verwenden Sie das integrierte Protokollierungsbibliotheksmodul , anstatt zu drucken.

Sie erstellen ein LoggerObjekt (z. B. logger) und geben danach jedes Mal, wenn Sie einen Debug-Druck einfügen, Folgendes ein:

logger.debug("Some string")

Sie können logger.setLevelzu Beginn des Programms den Ausgangspegel einstellen. Wenn Sie DEBUG einstellen, werden alle Debugs gedruckt. Wenn Sie INFO oder höher einstellen, werden alle Debugs sofort ausgeblendet.

Sie können es auch verwenden, um schwerwiegendere Dinge auf verschiedenen Ebenen (INFO, WARNING und ERROR) zu protokollieren.

mgiuca
quelle
12

Zunächst werde ich die Nominierung des Python- Protokollierungsframeworks unterstützen . Seien Sie jedoch ein wenig vorsichtig, wie Sie es verwenden. Insbesondere: Lassen Sie das Protokollierungsframework Ihre Variablen erweitern, und tun Sie es nicht selbst. Zum Beispiel anstelle von:

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

Stellen Sie sicher, dass Sie Folgendes tun:

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

Denn während sie ähnlich aussehen, verursacht die erste Version die repr () - Kosten, selbst wenn sie deaktiviert ist . Die zweite Version vermeidet dies. In ähnlicher Weise würde ich, wenn Sie Ihre eigenen rollen, etwas vorschlagen wie:

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

debug = debug_stdout

angerufen über:

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

Dies vermeidet wiederum den Overhead, wenn Sie ihn deaktivieren, indem Sie Folgendes tun:

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

debug = debug_noop

Der Aufwand für die Berechnung dieser Zeichenfolgen spielt wahrscheinlich keine Rolle, es sei denn, sie sind entweder 1) teuer in der Berechnung oder 2) die Debug-Anweisung befindet sich beispielsweise in der Mitte einer n ^ 3-Schleife oder so. Nicht, dass ich etwas darüber wissen würde.

pjz
quelle
Weitere Informationen zu diesem wichtigen Thema finden Sie unter "Optimierung" im Protokollierungs-Howto: docs.python.org/3/howto/logging.html#optimization
Martin CR
7

Ich weiß nichts über andere, aber ich wurde verwendet, um eine "globale Konstante" ( DEBUG) und dann eine globale Funktion ( debug(msg)) zu definieren, die msgnur gedruckt wird , wenn DEBUG == True.

Dann schreibe ich meine Debug-Anweisungen wie folgt:

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

... dann nehme ich Unit-Tests auf und habe das nie wieder gemacht! :) :)

Mac
quelle
Unit Testing ha. Okay, das ist eine andere Sache, die dann abgeholt werden muss :(
crazyaboutliv
1
Ich möchte Unit-Tests nicht entmutigen - es ist wichtig. Aber ich denke nicht, dass es ein Ersatz für die Protokollierung ist, auch nicht als Debugging-Technik. Ich drucke immer noch viel, um Dinge schnell zu testen.
mgiuca
@crazyaboutliv - Richtig durchgeführte Unit-Tests sind großartig. Werfen Sie einen Blick auf dieses Kapitel des Eintauchens in Python für eine bissige, prägnante, leicht zu verfolgende Präsentation
Mac
@mgiuca - Ich drucke auch schnell, aber es dauert nur ein paar Minuten print(), bis ich meinen Code auf das erforderliche Niveau gebracht habe, um den Test zu bestehen. Ich habe nie eine große Menge von print()überall. Protokollierung ist auch cool! :)
Mac
2
@mac Es sieht so aus, als ob Ihr Link jetzt ein explizites "www" erfordert - er wird jetzt hier gehostet .
Culix