Zum Inhalt springen

cat posts/debuggen-mit-pdb.md

Debuggen mit breakpoint() und pdb

Statt überall print zu streuen: Mit breakpoint() und pdb hältst Du Python-Code gezielt an, inspizierst Variablen und gehst Schritt für Schritt durch den Ablauf.

Wenn etwas nicht funktioniert, ist der erste Reflex oft:

print("bin hier")
print(spieler)
print(raum)
print(argument)

Das ist für kleine Fragen völlig okay. Aber nach kurzer Zeit ist der Code voller print(...)-Ausgaben, die Du später wieder entfernen musst. Außerdem siehst Du immer nur die Werte, die Du vorher ausdrücklich ausgegeben hast.

In Teil 8 der Python-Serie haben wir Exceptions behandelt. In Logging statt printgeplant ging es darum, was ein laufendes Programm dauerhaft protokollieren sollte.

Heute geht es um die gezielte Fehlersuche jetzt gerade.

Dafür bringt Python einen eigenen Debugger mit: pdb.

Mit pdb kannst Du ein Programm anhalten, Variablen ansehen, Ausdrücke auswerten und Zeile für Zeile weiterlaufen lassen.

Debugger statt print-Konfetti

Angenommen, im Dungeon funktioniert das Aufnehmen eines Gegenstands nicht richtig. Du könntest mehrere print(...)-Ausgaben einbauen:

print("verb:", verb)
print("argument:", argument)
print("gegenstaende:", raum.gegenstaende)

Das hilft kurzfristig, hat aber Nachteile:

  • Du musst vorher wissen, welche Werte interessant sind.
  • Du musst das Programm immer wieder neu starten.
  • Du veränderst den Code nur für die Fehlersuche.
  • Du musst die Ausgaben später wieder entfernen.
  • In Schleifen wird die Ausgabe schnell unübersichtlich.

Ein Debugger hält das Programm an einer bestimmten Stelle an. Danach kannst Du interaktiv untersuchen, was gerade im Speicher liegt.

Du kannst also im laufenden Programm fragen:

Wie sieht `spieler` gerade aus?
Was steht in `argument`?
Welche Gegenstände liegen im Raum?
Welche Zeile wird als Nächstes ausgeführt?
Wie bin ich überhaupt hier gelandet?

Genau dafür ist pdb gedacht.

breakpoint(): der einfachste Einstieg

Seit Python 3.7 gibt es die eingebaute Funktion breakpoint().

Du schreibst sie an die Stelle, die Dich interessiert:

def verarbeite_befehl(verb, argument, spieler, raum):
    breakpoint()

    if verb == "nimm":
        gegenstand = raum.nimm_gegenstand(argument)
        spieler.nimm(gegenstand)
        print(f"Du nimmst {gegenstand}.")

Startest Du das Programm und erreichst diese Zeile, hält Python an.

Im Terminal erscheint ein Prompt wie:

(Pdb)

Das bedeutet: Du bist jetzt im Debugger.

Das Programm läuft nicht weiter, bis Du im Debugger einen passenden Befehl eingibst.

Ein kleines Beispiel

Lege eine Datei debug_beispiel.py an:

def berechne_schaden(staerke, ruestung):
    schaden = staerke - ruestung
    breakpoint()
    return max(schaden, 0)


def main():
    hp = 100
    schaden = berechne_schaden(25, 10)
    hp = hp - schaden

    print(f"HP: {hp}")


main()

Starte das Programm:

python debug_beispiel.py

Die Ausführung hält bei breakpoint() an:

> debug_beispiel.py(3)berechne_schaden()
-> return max(schaden, 0)
(Pdb)

Die Zeile mit -> zeigt, welche Zeile als Nächstes ausgeführt wird.

Nun kannst Du Werte untersuchen:

(Pdb) p staerke
25
(Pdb) p ruestung
10
(Pdb) p schaden
15

Mit c läuft das Programm weiter:

(Pdb) c
HP: 85

Die wichtigsten pdb-Befehle

Im (Pdb)-Prompt gibst Du Debugger-Befehle ein.

Befehl Langform Bedeutung
h help Hilfe anzeigen
l list Quellcode um die aktuelle Zeile anzeigen
ll longlist mehr Quellcode für die aktuelle Funktion anzeigen
n next nächste Zeile ausführen, Funktionsaufrufe überspringen
s step nächste Zeile ausführen, in Funktionsaufrufe hineinsteigen
r return bis zum Ende der aktuellen Funktion laufen
c continue weiterlaufen bis zum nächsten Breakpoint
p p ausdruck Ausdruck ausgeben
pp pp ausdruck Ausdruck hübscher formatiert ausgeben
w where aktuellen Aufruf-Stack anzeigen
u up im Stack eine Ebene nach oben gehen
d down im Stack eine Ebene nach unten gehen
a args Argumente der aktuellen Funktion anzeigen
b break neuen Breakpoint setzen
q quit Debugging abbrechen

Die Kurzformen sind im Alltag sehr praktisch. Am Anfang kannst Du aber ruhig die Langformen verwenden.

Werte ansehen mit p und pp

Der häufigste Befehl ist p:

(Pdb) p schaden
15

p steht für print, ist aber ein pdb-Befehl, nicht die normale print(...)-Funktion.

Du kannst beliebige Python-Ausdrücke auswerten:

(Pdb) p staerke - ruestung
15
(Pdb) p schaden > 0
True

Für verschachtelte Daten ist pp oft angenehmer:

(Pdb) pp spieler.inventar
[
    Gegenstand(name='Fackel', beschreibung='Eine rußige Fackel.'),
    Gegenstand(name='Schlüssel', beschreibung='Ein schwerer Schlüssel.'),
]

pp steht für pretty print.

Python-Ausdrücke direkt ausführen

Im Debugger kannst Du nicht nur Werte ansehen, sondern auch Python-Ausdrücke ausführen.

(Pdb) p len(spieler.inventar)
2
(Pdb) p [gegenstand.name for gegenstand in spieler.inventar]
['Fackel', 'Schlüssel']

Du kannst sogar Werte verändern:

(Pdb) spieler.hp = 100
(Pdb) p spieler.hp
100

Das ist mächtig, aber gefährlich. Du veränderst den echten State des laufenden Programms.

Für Experimente ist das nützlich. Für eine saubere Fehlersuche solltest Du Dir merken, welche Änderungen Du im Debugger vorgenommen hast.

Wenn ein Name wie ein pdb-Befehl heißt

pdb interpretiert Eingaben zuerst als Debugger-Befehle.

Wenn Du eine Variable c hast und im Debugger eingibst:

(Pdb) c

läuft das Programm weiter, weil c für continue steht.

Um ausdrücklich Python-Code auszuführen, kannst Du ein Ausrufezeichen voranstellen:

(Pdb) !c

Das ist vor allem wichtig, wenn ein Variablenname mit einem pdb-Befehl kollidiert.

Auch Zuweisungen sind mit ! eindeutig:

(Pdb) !spieler.hp = 100

In vielen Fällen erkennt pdb Python-Ausdrücke auch ohne !. Bei Unklarheiten ist das Ausrufezeichen die sichere Variante.

next oder step?

Die beiden wichtigsten Bewegungsbefehle sind n und s.

n: nächste Zeile in derselben Funktion

n steht für next.

Es führt die aktuelle Zeile aus und hält bei der nächsten Zeile in derselben Funktion an.

Funktionsaufrufe werden dabei ausgeführt, aber nicht im Detail betreten.

(Pdb) n

Das ist meistens der richtige Befehl, wenn Du grob durch eine Funktion gehen möchtest.

s: in Funktionsaufrufe hinein

s steht für step.

Es führt die nächste Operation aus und steigt in aufgerufene Funktionen hinein.

(Pdb) s

Beispiel:

gegenstand = raum.nimm_gegenstand(argument)

Mit n wird die Methode nimm_gegenstand(...) vollständig ausgeführt.

Mit s springt pdb in diese Methode hinein, sodass Du dort Zeile für Zeile weiterdebuggen kannst.

Wenn Du wissen willst, warum eine aufgerufene Funktion ein falsches Ergebnis liefert, nimm s.

Wenn Dich nur das Ergebnis interessiert, nimm n.

Mit where, up und down den Stack verstehen

Wenn eine Funktion eine andere Funktion aufruft, entsteht ein Aufruf-Stack.

Im Dungeon kann das beispielsweise so aussehen:

main()
  verarbeite_befehl()
    raum.nimm_gegenstand()

Mit w oder where zeigt pdb diesen Stack:

(Pdb) w
  dungeon.py(230)<module>()
-> main()
  dungeon.py(196)main()
-> neuer_ort = verarbeite_befehl(...)
  dungeon.py(151)verarbeite_befehl()
-> gegenstand = raum.nimm_gegenstand(argument)
> dungeon.py(92)nimm_gegenstand()
-> gesuchter_name = name.strip().lower()

Das > markiert den aktuellen Frame.

Mit u gehst Du im Stack nach oben, also zum Aufrufer:

(Pdb) u

Mit d gehst Du wieder nach unten:

(Pdb) d

Der aktuelle Frame entscheidet, welche lokalen Variablen Du mit p sehen kannst.

In nimm_gegenstand(...) gibt es beispielsweise name und gesuchter_name.

Im aufrufenden verarbeite_befehl(...) gibt es dagegen verb, argument, spieler und raum.

Argumente anzeigen mit args

Mit a oder args zeigt pdb die Argumente der aktuellen Funktion:

(Pdb) a
self = <__main__.Raum object at 0x...>
name = 'fackel'

Das ist praktisch, wenn Du schnell prüfen willst, mit welchen Werten eine Funktion aufgerufen wurde.

Gerade bei Methoden ist sichtbar, welches Objekt gerade als self verwendet wird.

Quellcode anzeigen mit list und longlist

Mit l zeigt pdb einige Zeilen Quellcode um die aktuelle Position herum:

(Pdb) l
 88     def nimm_gegenstand(self, name):
 89         gesuchter_name = name.strip().lower()
 90
 91         for gegenstand in self.gegenstaende:
 92  ->         if gegenstand.name.lower() == gesuchter_name:
 93                 self.gegenstaende.remove(gegenstand)

Mit ll zeigt pdb mehr Kontext für die aktuelle Funktion:

(Pdb) ll

Das ist hilfreich, wenn Du nicht mehr genau weißt, wo Du Dich befindest.

Bis zum Ende einer Funktion laufen

Mit r oder return läuft pdb bis zum Ende der aktuellen Funktion:

(Pdb) r

Das ist nützlich, wenn Du in eine Funktion hineingestiegen bist, aber nicht jede weitere Zeile einzeln ausführen möchtest.

Nach dem Return zeigt pdb den Rückgabewert an. In aktuellen pdb-Versionen kannst Du ihn außerdem mit retval erneut anzeigen lassen:

(Pdb) retval

Für den Anfang reicht die Regel:

  • n: eine Zeile weiter
  • s: in Funktionsaufrufe hinein
  • r: aus der aktuellen Funktion heraus
  • c: komplett weiterlaufen

Breakpoints im Debugger setzen

Du musst Breakpoints nicht immer mit breakpoint() in den Code schreiben.

Im pdb-Prompt kannst Du mit b oder break neue Breakpoints setzen:

(Pdb) b 42

Das setzt einen Breakpoint in Zeile 42 der aktuellen Datei.

Du kannst auch eine Funktion angeben:

(Pdb) b verarbeite_befehl

Oder eine andere Datei:

(Pdb) b dungeon.py:150

Mit c läuft das Programm weiter, bis ein Breakpoint erreicht wird:

(Pdb) c

Alle Breakpoints anzeigen:

(Pdb) b

Einen Breakpoint löschen:

(Pdb) clear 1

Die Zahl ist die Breakpoint-Nummer, die pdb beim Setzen oder Auflisten anzeigt.

Conditional Breakpoints

Manchmal willst Du nur anhalten, wenn eine bestimmte Bedingung erfüllt ist.

Beispiel:

(Pdb) b dungeon.py:150, argument == "fackel"

Dann stoppt pdb an dieser Zeile nur, wenn argument den Wert "fackel" hat.

Das ist besonders nützlich in Schleifen oder bei Funktionen, die sehr oft aufgerufen werden.

Du kannst Bedingungen auch nachträglich ändern:

(Pdb) condition 1 argument == "schluessel"

Oder entfernen:

(Pdb) condition 1

Ein Beispiel im Dungeon

Angenommen, der Befehl nimm fackel funktioniert nicht.

Im Code aus Teil 9 gibt es diese Funktion:

def verarbeite_befehl(
    verb,
    argument,
    spieler,
    raum,
    raeume,
    besuchte_raeume,
):
    if verb == "nimm":
        if not argument:
            raise UngueltigerBefehlError(
                "Was möchtest Du nehmen?"
            )

        gegenstand = raum.nimm_gegenstand(argument)
        spieler.nimm(gegenstand)

        print(f"Du nimmst {gegenstand}.")
        print(gegenstand.untersuche())

        return None

Setze einen Breakpoint direkt vor dem Aufnehmen:

        breakpoint()
        gegenstand = raum.nimm_gegenstand(argument)

Starte das Spiel und gib ein:

nimm fackel

pdb hält an.

Jetzt kannst Du den State untersuchen:

(Pdb) p verb
'nimm'
(Pdb) p argument
'fackel'
(Pdb) p raum.name
'Halle'
(Pdb) pp raum.gegenstaende
[Gegenstand(name='Fackel', beschreibung='Eine rußige, aber noch brauchbare Fackel.')]

Wenn argument leer ist, liegt der Fehler wahrscheinlich beim Zerlegen des Befehls.

Wenn raum.gegenstaende leer ist, liegt der Gegenstand nicht mehr im Raum.

Wenn dort "Fackel" liegt, Du aber nach "fackel" suchst, solltest Du die Groß- und Kleinschreibung prüfen.

Mit s kannst Du in raum.nimm_gegenstand(argument) hineinsteigen:

(Pdb) s

Dort prüfst Du weiter:

(Pdb) p name
'fackel'
(Pdb) n
(Pdb) p gesuchter_name
'fackel'
(Pdb) p gegenstand.name.lower()
'fackel'

Damit findest Du nicht nur heraus, dass etwas falsch ist, sondern auch wo der State vom erwarteten Wert abweicht.

Post-mortem-Debugging nach einem Absturz

Manchmal hast Du keinen Breakpoint gesetzt, sondern das Programm ist bereits mit einer Exception abgestürzt.

In einer interaktiven Python-Session kannst Du danach pdb.pm() verwenden:

import pdb

Dann löst Du versehentlich einen Fehler aus:

int("viel")

Python zeigt einen Traceback. Direkt danach:

pdb.pm()

pdb springt an die Stelle, an der die Exception aufgetreten ist. Dort kannst Du Variablen inspizieren.

In einer Datei ist häufig pdb.post_mortem(...) praktischer:

import pdb
import traceback


try:
    main()
except Exception:
    traceback.print_exc()
    pdb.post_mortem()

Damit wird der Traceback ausgegeben und anschließend der Debugger an der Fehlerstelle geöffnet.

Diese Form ist nur für lokale Fehlersuche gedacht. In produktivem Code solltest Du nicht pauschal alle Exceptions so abfangen.

Ein Skript direkt mit pdb starten

Du kannst ein Programm auch direkt unter Kontrolle von pdb starten:

python -m pdb dungeon.py

pdb hält dann sehr früh an, noch bevor Dein Programm normal losläuft.

Mit c startest Du die Ausführung:

(Pdb) c

Setzt Du vorher Breakpoints, kannst Du gezielt an bestimmten Stellen anhalten:

(Pdb) b verarbeite_befehl
(Pdb) c

Bei einer unbehandelten Exception landet python -m pdb ... außerdem im Post-mortem-Debugging.

Für die Praxis ist diese Variante nützlich, wenn Du keinen breakpoint() in den Quellcode schreiben möchtest.

Mit -c direkt einen pdb-Befehl ausführen

Beim Start mit python -m pdb kannst Du einen Debugger-Befehl mitgeben:

python -m pdb -c continue dungeon.py

Damit startet pdb und führt sofort continue aus.

Das Programm läuft also normal los. Wenn es später mit einer unbehandelten Exception abstürzt, kannst Du die Stelle im Debugger untersuchen.

Du kannst auch direkt einen Breakpoint setzen:

python -m pdb -c "break verarbeite_befehl" dungeon.py

Dann hält pdb beim Aufruf dieser Funktion an.

Für den Einstieg ist breakpoint() im Code oft einfacher. Die Kommandozeile ist praktisch, wenn Du den Quellcode nicht anfassen möchtest.

breakpoint() ersetzen oder abschalten

breakpoint() ruft nicht fest und unveränderlich pdb auf. Standardmäßig landet der Aufruf zwar bei pdb.set_trace(), aber das Verhalten lässt sich über PYTHONBREAKPOINT beeinflussen.

Breakpoints deaktivieren

Setzt Du PYTHONBREAKPOINT=0, macht breakpoint() nichts.

Unter Linux, macOS oder in einer typischen Shell:

PYTHONBREAKPOINT=0 python dungeon.py

Unter Windows PowerShell:

$env:PYTHONBREAKPOINT = "0"
python dungeon.py

Unter Windows cmd.exe:

set PYTHONBREAKPOINT=0
python dungeon.py

Das ist nützlich, wenn noch breakpoint()-Aufrufe im Code stehen, Du sie aber für einen Lauf ignorieren möchtest.

Trotzdem gilt: Vor einem Commit oder Deployment sollten versehentliche Breakpoints entfernt werden.

Einen anderen Debugger verwenden

PYTHONBREAKPOINT kann auch auf eine andere Debugger-Funktion zeigen.

Beispiel mit ipdb, falls installiert:

PYTHONBREAKPOINT=ipdb.set_trace python dungeon.py

Der Code bleibt gleich:

breakpoint()

Von außen entscheidest Du, welcher Debugger tatsächlich verwendet wird.

Das ist der Grund, warum breakpoint() moderner und flexibler ist als der ältere direkte Aufruf:

import pdb
pdb.set_trace()

Wann pdb, wann Logging?

pdb und Logging lösen unterschiedliche Probleme.

pdb

pdb ist interaktiv.

Du verwendest es, wenn Du gerade aktiv wissen willst:

  • Warum ist diese Variable falsch?
  • Welche Zeile verändert diesen State?
  • Warum wird dieser Branch betreten?
  • Was gibt diese Funktion wirklich zurück?
  • Welche Werte liegen im aktuellen Stack?

pdb hält das Programm an und wartet auf Deine Eingabe.

Das ist perfekt für lokale Fehlersuche, aber schlecht für ein dauerhaft laufendes Programm.

Logging

Logging ist nicht interaktiv.

Du verwendest es, wenn Du später nachvollziehen willst:

  • Wann wurde das Programm gestartet?
  • Welche Datei wurde geladen?
  • Welche Eingabe wurde verarbeitet?
  • Welche Operation ist fehlgeschlagen?
  • Was passierte kurz vor einer Exception?

Logging ist für Dauerbetrieb, Cronjobs, Bots, Dienste und Fehlersuche auf fremden Systemen viel besser geeignet.

Kurz gesagt:

  • pdb: Was passiert genau hier und jetzt?
  • Logging: Was ist über die Zeit passiert?

pdb und IDE-Debugger

Viele Editoren und IDEs besitzen komfortable Debugger-Oberflächen. Visual Studio Code, PyCharm und andere Tools können Breakpoints visuell setzen, Variablen in Panels anzeigen und Call Stacks grafisch darstellen.

Trotzdem lohnt sich pdb.

pdb funktioniert:

  • ohne zusätzliche Installation,
  • direkt im Terminal,
  • auf Servern per SSH,
  • in kleinen Skripten,
  • in Umgebungen ohne IDE,
  • immer dann, wenn nur Python selbst verfügbar ist.

Wer pdb versteht, versteht auch die Grundideen grafischer Debugger besser: Breakpoints, Stack Frames, Step Into, Step Over und Continue.

Debugging als Vorgehen

Ein Debugger ersetzt nicht das Denken. Er macht den tatsächlichen Ablauf sichtbar.

Eine hilfreiche Reihenfolge:

  1. Fehler reproduzieren: Welche Eingabe oder welcher Ablauf erzeugt das Problem zuverlässig?
  2. Erwartung formulieren: Welcher Wert sollte an einer bestimmten Stelle stehen?
  3. Breakpoint setzen: Halte kurz vor der verdächtigen Stelle an.
  4. State prüfen: Stimmen Eingabe, Objektzustand und Rückgabewerte?
  5. Schrittweise weitergehen: Nutze n und s, bis der Wert falsch wird.
  6. Ursache beheben: Entferne nicht nur das Symptom.
  7. Breakpoint entfernen: Der Code soll nicht unbeabsichtigt anhalten.
  8. Test oder Log ergänzen: Damit derselbe Fehler später schneller auffällt.

Der wichtigste Moment ist häufig der Übergang von „der Wert ist noch richtig“ zu „der Wert ist falsch“. Genau diesen Übergang suchst Du mit dem Debugger.

Stolperfallen

  • breakpoint() im Code vergessen: Im Betrieb hält das Programm an und wartet auf Eingabe. Vor Commit oder Deployment entfernen.

  • n und s verwechseln: n bleibt in der aktuellen Funktion. s steigt in Funktionsaufrufe hinein.

  • Zu früh mit s in fremden Code springen: Wenn Du in Bibliothekscode landest, kannst Du mit r aus der Funktion herauslaufen oder mit c fortsetzen.

  • Im Debugger echten State verändern: Zuweisungen im (Pdb)-Prompt wirken im laufenden Programm.

  • Variablennamen mit pdb-Befehlen verwechseln: Bei Kollisionen verwende p variable oder !variable.

  • q mit normalem Beenden verwechseln: q bricht das Debugging ab und beendet das Programm über eine Exception.

  • Post-mortem-Code im produktiven Programm lassen: Ein pauschales except Exception: pdb.post_mortem() gehört nur in lokale Fehlersuche.

  • Alles mit dem Debugger lösen wollen: Wiederkehrende Fehler sollten durch Tests, bessere Fehlerbehandlung oder Logging dauerhaft abgesichert werden.

  • Geheimnisse im Debugger anzeigen: Im Debugger kannst Du Tokens, Passwörter oder personenbezogene Daten sehen. Sei damit genauso vorsichtig wie mit Logs.

  • Breakpoints in asynchronem oder nebenläufigem Code unterschätzen: Ein Breakpoint hält den laufenden Thread beziehungsweise Prozess an und kann dadurch andere Abläufe blockieren.

Kompakte Übersicht

Ziel Befehl
Debugger im Code öffnen breakpoint()
Programm mit pdb starten python -m pdb skript.py
direkt loslaufen python -m pdb -c continue skript.py
Breakpoints deaktivieren PYTHONBREAKPOINT=0 python skript.py
Hilfe anzeigen h
Quellcode anzeigen l oder ll
nächste Zeile n
in Funktion hinein s
aus Funktion heraus r
weiterlaufen c
Ausdruck anzeigen p ausdruck
hübsch anzeigen pp ausdruck
Stack anzeigen w
Stack nach oben u
Stack nach unten d
Funktionsargumente anzeigen a
Breakpoint setzen b zeile oder b funktion
Debugging abbrechen q

Übungen

1. Einen Breakpoint setzen

Lege eine Datei debug_uebung.py mit folgendem Inhalt an:

def verdopple(zahl):
    ergebnis = zahl * 2
    breakpoint()
    return ergebnis


wert = verdopple(21)
print(wert)

Starte die Datei und gib im pdb-Prompt aus:

  • zahl
  • ergebnis
  • zahl + ergebnis
Lösung Programm starten:
python debug_uebung.py
Im Debugger:
(Pdb) p zahl
21
(Pdb) p ergebnis
42
(Pdb) p zahl + ergebnis
63
(Pdb) c
Danach läuft das Programm weiter und gibt `42` aus.

2. next und step vergleichen

Nutze dieses Programm:

def berechne_bonus(level):
    return level * 10


def berechne_gold(level):
    basis = 50
    bonus = berechne_bonus(level)
    return basis + bonus


breakpoint()
gold = berechne_gold(3)

print(gold)

Gehe einmal mit n über die Zeile gold = berechne_gold(3) und einmal mit s.

Lösung Mit `n` führt pdb `berechne_gold(3)` aus und hält danach bei der nächsten Zeile im äußeren Code an. Mit `s` steigt pdb in `berechne_gold(...)` hinein. Dort kannst Du anschließend mit weiterem `s` auch in `berechne_bonus(...)` hineingehen.

3. Den Stack anzeigen

Setze in diesem Programm einen Breakpoint in innen(...):

def innen(x):
    breakpoint()
    return 10 / x


def mitte(x):
    return innen(x)


def aussen(x):
    return mitte(x)


print(aussen(2))

Zeige mit pdb den Aufruf-Stack an und wechsle eine Ebene nach oben.

Lösung Im Debugger:
(Pdb) w
(Pdb) u
(Pdb) a
`w` zeigt den Stack. `u` wechselt zum Aufrufer. `a` zeigt die Argumente des aktuellen Frames. Mit `d` gehst Du wieder zurück in den jüngeren Frame.

4. Post-mortem-Debugging verwenden

Starte eine Python-REPL und führe aus:

def teile(a, b):
    return a / b


teile(10, 0)

Nach dem Traceback:

import pdb
pdb.pm()

Prüfe im Debugger die Werte von a und b.

Lösung Im Debugger:
(Pdb) p a
10
(Pdb) p b
0
(Pdb) q
`pdb.pm()` springt in den Frame, in dem die Exception aufgetreten ist.

Weiterlesen

0 Kommentare

Noch keine Kommentare. Sei der/die Erste!