Wie man ein falsches Programm debuggt
Debuggen heißt herauszufinden, warum ein Programm das Falsche tut, und es dann zu ändern. Die meiste Arbeit ist nicht das Tippen der Korrektur. Sie besteht darin zu wissen, welche von hundert Stellen man ansehen muss.
Raten und wahlloses Ändern kann einen Nachmittag kosten. Immer nur eine Sache zu prüfen dauert Minuten. Diese Lektion zeigt, wie.
Am Ende dieser Lektion
Notiz
Ich kann einen Fehler finden, indem ich die Fehlermeldung lese und immer nur eine Sache prüfe.
Schlüsselwörter
| Begriff | Was er bedeutet |
|---|---|
| Bug | ein Fehler im Programm, der falsches Verhalten auslöst |
| Reproduzieren | den Fehler gezielt und gleich noch einmal auslösen |
| Traceback | die Liste der Aufrufe, die Python bei einem Fehlerabbruch ausgibt |
| Hypothese | eine Vermutung zur Ursache, die eine Prüfung widerlegen kann |
| Print-Kontrolle | eine Zeile, die einen Wert anzeigt, um zu sehen, was das Programm wirklich hält |
| Halbieren | die Mitte des Rests prüfen, sodass jede Prüfung die Hälfte ausschließt |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.
Zuerst den Fehler auf Abruf auslösen
Was Sie nicht sehen können, können Sie nicht beheben. Suchen Sie, bevor Sie etwas ändern, eine Eingabe, die den Fehler jedes Mal auslöst, und behalten Sie sie.
Hier mittelt ein kleines Programm die Umsätze einer Datei, eine Zeile pro Tag. In den Daten fehlt ein Wert. Legen Sie zuerst Ordner und Datei an.
Ordner für die Lektion anlegen
mkdir -p ~/fehlersucheHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
In den Ordner wechseln
cd ~/fehlersucheHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Die Umsatzdatei schreiben
printf 'mo 120\ndi 80\nmi fehlt\ndo 200\n' > umsaetze.txtHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Das Berichtsprogramm schreiben
printf 'def zerlege(zeile):\n tag, betrag = zeile.split()\n return tag, int(betrag)\n\n\ndef mittelwert(zeilen):\n summe = 0\n for zeile in zeilen:\n tag, betrag = zerlege(zeile)\n summe = summe + betrag\n return summe / len(zeilen)\n\n\nprint(mittelwert(open("umsaetze.txt").read().splitlines()))\n' > bericht.pyHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Starten und den Abbruch ansehen
python3 bericht.pyHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Einen Traceback von unten nach oben lesen
Ein Traceback listet die Aufrufe auf, die beim Abbruch offen waren. Der neueste Aufruf steht unten, also lesen Sie von unten.
Die letzte Zeile sagt, was schiefging: ValueError mit einer Meldung. Die File-Zeile darüber sagt, wo: eine Datei, eine Zeilennummer und eine Funktion. Die Zeilen darüber zeigen, wie das Programm dorthin kam.
Nur die File-Zeilen anzeigen
python3 bericht.py 2>&1 | grep "File"Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Eine Sache prüfen, dann die nächste
Der Fehler zeigt, wo das Programm stehen blieb, nicht warum die Daten falsch waren. Bilden Sie also eine Hypothese: eine Vermutung, die eine Prüfung widerlegen kann.
Hier lautet sie: Eine Zeile der Daten ist keine Zahl. Suchen Sie in der Datei danach. Findet die Prüfung nichts, war die Vermutung falsch, und auch das ist Fortschritt.
Die Daten nach dem Text durchsuchen
grep -n "fehlt" umsaetze.txtHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Eine schnelle Korrektur kann den nächsten Fehler verbergen
Zeile 3 lautet mi fehlt: An dem Tag gab es keinen Umsatzwert. Am schnellsten zählen Sie ihn als 0. Probieren Sie es aus und starten Sie das Programm erneut.
Einen fehlenden Wert als 0 zählen
sed -i 's| return tag, int(betrag)| if betrag == "fehlt":\n return tag, 0\n return tag, int(betrag)|' bericht.pyHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Erneut starten
python3 bericht.pyHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Kein Fehler heißt nicht fehlerfrei
Das Programm lief und gab 100.0 aus. Der Mittelwert der drei Tage mit Werten, 120, 80 und 200, ist aber 133,3. Das Programm ist falsch und sagt nichts.
Jetzt gibt es keinen Traceback zu lesen. Setzen Sie eine Print-Kontrolle dorthin, wo addiert wird, und sehen Sie, was wirklich vorliegt.
Jeden Tag beim Addieren ausgeben
sed -i 's| summe = summe + betrag| print(tag, betrag)\n summe = summe + betrag|' bericht.pyHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Starten und jede Zeile lesen
python3 bericht.pyHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Bei vielen Stufen das Problem halbieren
Das Programm hat vier Stufen. Prüfen Sie zuerst die mittlere. Stimmt die Summe, liegt der Fehler dahinter. Stimmt sie nicht, liegt er davor. Jede Prüfung schließt die Hälfte aus.
So findet ein Team, welche von tausend Änderungen eine Funktion kaputt gemacht hat.
Beispiel: die Stufen prüfen
| Stufe | Soll | Ist | Urteil |
|---|---|---|---|
| Datei lesen | 4 Zeilen | 4 Zeilen | In Ordnung |
| Jeden Betrag lesen | 120, 80, fehlt, 200 | 120, 80, 0, 200 | Die 0 ist eine erfundene Zahl |
| Addieren | 400 | 400 | In Ordnung |
| Durch die gezählten Tage teilen | 400 / 3 = 133,3 | 400 / 4 = 100.0 | Ein Tag ohne Wert wurde mitgezählt |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.
Das Programm mit der Korrektur neu schreiben
printf 'def zerlege(zeile):\n tag, betrag = zeile.split()\n if not betrag.isdigit():\n return None\n return tag, int(betrag)\n\n\ndef mittelwert(zeilen):\n summe = 0\n anzahl = 0\n for zeile in zeilen:\n paar = zerlege(zeile)\n if paar is not None:\n summe = summe + paar[1]\n anzahl = anzahl + 1\n return summe / anzahl\n\n\nprint(round(mittelwert(open("umsaetze.txt").read().splitlines()), 1))\n' > bericht.pyHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Das korrigierte Programm starten
python3 bericht.pyHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Ein häufiger Fehler
Warnung
Viele ändern Code, bevor sie die Ursache kennen, und ändern etwas anderes, wenn das nicht hilft. Nach fünf Änderungen weiß niemand, welche geholfen hat. Prüfen Sie zuerst, ändern Sie eine Sache und starten Sie erneut.
Weiterdenken: die Änderung finden, die es kaputt machte
Ein Team hält jede Änderung in Git fest. Tritt ein Fehler auf, ist eine alte Version gut und die neueste schlecht. Der Befehl git bisect lässt Sie die mittlere Version testen und halbiert den Verlauf, bis eine Änderung übrig bleibt.
Schreiben Sie die Schritte für 1000 Änderungen auf. Wie viele Versionen testen Sie höchstens?