mitmario.dev

Der Plan

Python Sandbox 5 Min Lesezeit 2 BeispieleLektion 1 von 8

Die erste Fassung des Kontoauszugs reicht für einen Monat. Sie stammt aus Abschnitt 12, liest ein, ordnet jede Ausgabe einer Kategorie zu und zählt zusammen. Aber die Regeln stehen im Code. Ein Export, der anders anfängt oder anders kodiert ist, bringt sie aus dem Tritt. Und ob sie nach der nächsten Änderung noch richtig rechnet, sagt einem niemand.

In diesem Abschnitt wird daraus ein Werkzeug, das man wirklich jeden Monat benutzt. Neuen Stoff gibt es kaum. Alles, was du dafür brauchst, kam im Kurs schon einmal vor, nur muss es diesmal zusammenpassen.

Und wie beim Spritkostenrechner früh im Kurs steht am Anfang kein Code, sondern ein Zettel.

Was hineingeht

Was das Online-Banking liefert
from pathlib import Path

zeilen = Path("kontoauszug.csv").read_text(encoding="utf-8").splitlines()
print(len(zeilen), "Zeilen, die ersten acht:")
for nummer, zeile in enumerate(zeilen[:8], start=1):
    print(nummer, zeile)

Hinein geht der Export aus dem Online-Banking, drei Monate eines Girokontos. Schon in den ersten Zeilen stecken zwei Dinge, die die erste Fassung nicht kannte.

Die Zeile mit den Spaltennamen steht nicht oben, sondern in Zeile 5. Davor stehen das Konto, der Zeitraum und der Kontostand, und dann kommt eine leere Zeile. Viele Banken machen das so, jede ein bisschen anders.

Außerdem steht neben dem Empfänger ein Verwendungszweck, und bei manchen Buchungen erfährt man nur dort, worum es geht. Beim Gehalt steht in der Spalte Empfänger die Firma, die es überweist. Dass es das „Gehalt Oktober“ ist, steht erst im Verwendungszweck.

Was man der Datei nicht ansieht, ist ihre Kodierung. Diese hier ist in UTF-8 geschrieben, wie alle Dateien im Kurs. Manche Banken schreiben ihren Export aber in der alten Windows-Kodierung, und dann bricht das Lesen als UTF-8 schon beim ersten Umlaut ab, dem ä in „Umsätze“ ganz oben. Darum geht es in der nächsten Lektion.

Was herauskommen soll

Am Ende steht ein Aufruf, wie man ihn von Werkzeugen kennt: python main.py kontoauszug.csv --monat 2026-09. Im Terminal erscheint dann eine Übersicht über den Monat. Oben eine Tabelle mit den Ausgaben je Kategorie, die größte zuerst, darunter, was hereinkam, was hinausging und was bleibt.

Daneben entsteht eine Datei für die Tabellenkalkulation, in der jede Buchung des Monats mit ihrer Kategorie steht. Wenn du dort nachsehen willst, welche Ausgaben unter Lebensmittel gelandet sind, filterst du eine Spalte und musst nichts mehr von Hand abtippen.

Was nicht herauskommen soll, gehört auch auf den Zettel. In den Export wird nichts zurückgeschrieben, keine Bank wird im Netz gefragt, und zwischen zwei Aufrufen merkt sich das Werkzeug nichts. Jeder Monat ist ein neuer Aufruf mit einer neuen Datei.

Die Teile

Zwischen Datei und Übersicht liegen vier Schritte, und jeder bekommt ein eigenes Modul:

  1. einlesen.py macht aus der Datei eine Liste von Buchungen, mit Datum als date und Betrag als Decimal, egal in welcher der beiden Kodierungen sie kommt.
  2. kategorien.py liest die Regeln aus regeln.csv und gibt jeder Buchung ihre Kategorie.
  3. bericht.py fasst einen Monat zusammen und gibt die Übersicht als Text zurück.
  4. test_auswerter.py prüft die drei Teile mit pytest, damit eine Änderung an den Regeln nicht still etwas anderes kaputt macht.

main.py setzt alles zusammen und liest, was beim Aufruf dahintersteht. Die Reihenfolge ist die, in der die Daten fließen. Jeder Teil braucht nur die Teile davor, und keiner muss wissen, wie ein anderer innen aussieht. Früher stand dieselbe Aufteilung in den Funktionen einer Datei. Diesmal steht sie in Modulen.

Ein Gerüst, das schon läuft

Ein Gerüst aus Attrappen
from bericht import uebersicht
from einlesen import lies_kontoauszug
from kategorien import kategorisiere, lies_regeln

# So soll es am Ende aussehen, nach Lektion 19.6:
#   $ python main.py kontoauszug.csv --monat 2026-09
#   kontoauszug.csv: 29 Buchungen, utf-8
#   Übersicht 2026-09: 10 Buchungen
#   (eine Tabelle mit den Ausgaben je Kategorie)
#   Einnahmen: 2.625,00 €
#   Ausgaben: 1.423,00 €
#   Bleibt: 1.202,00 €
#   Bericht: bericht-2026-09.csv


def main():
    buchungen, kodierung = lies_kontoauszug("kontoauszug.csv")
    regeln = lies_regeln("regeln.csv")
    for buchung in buchungen:
        buchung.kategorie = kategorisiere(buchung, regeln)

    print(f"kontoauszug.csv: {len(buchungen)} Buchungen, {kodierung}")
    print(uebersicht(buchungen, "2026-09"))


if __name__ == "__main__":
    main()

Das Werkzeug kann schon laufen, bevor eine einzige Funktion etwas Echtes tut. Jede Funktion steht mit Namen, Parametern und Docstring da und gibt etwas Festes zurück. Das ist eine Attrappe, so wie die Pappfernseher, die ein Möbelhaus in die Schrankwand stellt. lies_kontoauszug liefert zwei Buchungen, die gar nicht aus der Datei kommen, kategorisiere sagt zu allem Sonstiges, und uebersicht zählt nur.

Das sieht nach Spielerei aus. Tatsächlich ist es der wichtigste Teil des Plans, weil im Gerüst festgelegt ist, was zwischen den Teilen hin und her geht. lies_kontoauszug gibt die Buchungen und die Kodierung zusammen zurück. kategorisiere bekommt eine Buchung und die Regeln und gibt den Namen einer Kategorie zurück. Und uebersicht gibt einen Text zurück, statt ihn auszugeben.

Wenn das stimmt, lässt sich jede Attrappe einzeln gegen echten Code tauschen, und main.py merkt davon nichts. Ganz oben in main.py steht im Kommentar, wie es am Ende aussehen soll.

Warum der Plan schon die halbe Arbeit ist

Ein paar Entscheidungen sind in diesem Gerüst schon gefallen, und für jede gibt es einen Grund aus einem früheren Abschnitt. Das Datum ist ein date, weil ein Datum als Text falsch sortiert wird (Lektion 8.7) und weil man aus einem date den Monat holen kann. Der Betrag ist ein Decimal, weil es um Geld geht (Lektion 10.5). Die Regeln stehen in einer Datei, weil man sie öfter ändert als den Code. Und die Übersicht kommt als Text zurück, weil sich ein Text in einem Test prüfen lässt, eine Ausgabe auf dem Bildschirm dagegen nur schwer.

Jede dieser Entscheidungen kostet jetzt einen Satz. Nach drei Wochen Bauzeit kostet jede einen Nachmittag, weil dann schon Code an der alten Form hängt. Der Plan passt auf eine Seite und ist trotzdem die halbe Arbeit, denn was danach noch fehlt, sind nur noch Lücken, bei denen schon klar ist, was hineingehört.

Ein Modul je Aufgabe

Die Attrappen werden eine nach der anderen gegen den echten Teil getauscht, und in jeder Aufgabe arbeitest du in genau einem Modul. Die Teile davor liegen im Dateibaum unter Dateien, so wie sie nach der Lektion davor aussehen, und main.py wächst mit. Wie weit das Werkzeug schon ist, siehst du in jeder Lektion am Befehl mit python main.py in der Befehlsleiste.

Zum Mitnehmen

Am Anfang eines Werkzeugs steht ein Zettel mit dem, was hineingeht, dem, was herauskommen soll, und den Teilen dazwischen. Jeder Teil wird ein Modul mit einer Aufgabe, und Namen, Parameter und Rückgaben der Funktionen liegen fest, bevor auch nur eine davon etwas Echtes tut. Gebaut wird in der Reihenfolge vom Export zur Übersicht, und bis dahin halten Attrappen das Gerüst am Laufen.

Jetzt du

Basis Konto, kostenlos

Im Editor änderst du die Beispiele dieser Lektion und lässt sie gleich laufen. So merkst du am schnellsten, ob es sitzt.

Dafür brauchst du das Basis Konto. Es kostet nichts, und ein Passwort gibt es auch nicht.

In diesem Kurs läuft dein Code auf einem Server. Dafür hat das Basis Konto 1 Stunde im Monat, mehr Zeit gibt es mit dem Premium Konto.

Was in dieser Lektion steckt

  • Artikel mit 2 Beispielen zum Ausprobieren

    Steht hier, ohne Konto lesbar.