mitmario.dev

Deutsche Zahlen und Daten einlesen

Python Sandbox 4 Min Lesezeit 5 BeispieleLektion 2 von 8

Ein Kontoauszug besteht aus Beträgen und Daten, und mit beiden will man rechnen. Was kam herein, was ging hinaus, von wann bis wann reicht der Auszug? Eingelesen ist aber jeder Wert darin Text, und das passt nur für Namen und Telefonnummern.

Die Werkzeuge dafür kennst du schon, das Umwandeln deutscher Zahlen, Decimal und strptime. Hier werden daraus zwei Funktionen, die du in jedem Programm wieder benutzen kannst, das deutsche Tabellen liest.

Alles nur Text

Alles nur Text
import csv

with open("konto.csv", encoding="utf-8-sig", newline="") as datei:
    buchungen = list(csv.DictReader(datei, delimiter=";"))

tage = []
for buchung in buchungen:
    tage.append(buchung["Buchungstag"])
print("Vom", min(tage), "bis", max(tage))
print(buchungen[0]["Betrag"] + buchungen[1]["Betrag"])

Die Daten in konto.csv reichen vom 29. September bis zum 30. Oktober, das Neueste oben, so wie die Bank sie liefert. Mit min und max über die Buchungstage kommt trotzdem „vom 02.10.2026 bis 30.10.2026“ heraus. Text wird Zeichen für Zeichen verglichen, und 0 kommt vor 2, egal welcher Monat dahinter steht. Das kennst du vom Sortieren nach Datum.

Noch deutlicher ist die zweite Zeile. Zwei Beträge mit + ergeben einen zusammengeklebten Text statt einer Summe.

Eine Funktion für Beträge

Eine Funktion für Beträge
from decimal import Decimal


def zahl_aus_text(text):
    """Macht aus einem deutschen Betrag wie "-1.234,56" ein Decimal."""
    return Decimal(text.replace(".", "").replace(",", "."))


print(zahl_aus_text("-1.234,56"))
print(repr(zahl_aus_text("2.580,00")))
print(zahl_aus_text("-1.234,56") + zahl_aus_text("2.580,00"))

zahl_aus_text geht den Weg aus Lektion 6.4, erst die Tausenderpunkte weg und dann das Komma zum Punkt. Nur steht am Ende kein float(), sondern ein Decimal. Ein Kontoauszug ist Geld, und Geld rechnet man genau.

Der Text aus der Datei geht dabei direkt an Decimal, ohne Umweg über eine Kommazahl, und die Nachkommastellen bleiben genau so, wie sie in der Datei standen, also Decimal('2580.00').

Bei der Reihenfolge der beiden replace lauert dieselbe Falle wie bei den deutschen Zahlen. Andersherum stünden in -1.234,56 erst zwei Punkte, und am Ende kämen minus 123456 Euro heraus.

Eine Funktion für Daten

Eine Funktion für Daten
from datetime import datetime


def datum_aus_text(text):
    """Macht aus einem deutschen Datum wie "03.09.2026" ein date."""
    return datetime.strptime(text, "%d.%m.%Y").date()


tage = [datum_aus_text("02.10.2026"), datum_aus_text("30.10.2026"), datum_aus_text("29.09.2026")]
print(repr(tage[0]))
print("Vom", min(tage).strftime("%d.%m.%Y"), "bis", max(tage).strftime("%d.%m.%Y"))
print(datum_aus_text("31.09.2026"))

Für ein Datum gibt es strptime mit dem Muster "%d.%m.%Y", und dahinter .date(), weil eine Buchung keine Uhrzeit hat. Mit repr() siehst du, was dabei herauskommt. datetime.date(2026, 10, 2) ist ein Datum, so geschrieben, wie man es in Python selbst anlegen würde. Mit solchen Werten stimmen auch min und max, und mit strftime werden sie für die Ausgabe wieder deutsch.

Die letzte Zeile zeigt etwas, das bei strptime schon eingebaut ist. Einen 31. September gibt es nicht, und das Programm endet mit ValueError: day 31 must be in range 1..30 for month 9 in year 2026. Vor Python 3.14 heißt es knapper day is out of range for month. Ein kaputtes Datum fällt also auf, und zwar mit einem ValueError, wie du ihn aus Abschnitt 9 kennst.

Was das Minus heißt

Was das Minus heißt
import csv
from decimal import Decimal


def zahl_aus_text(text):
    """Macht aus einem deutschen Betrag wie "-1.234,56" ein Decimal."""
    return Decimal(text.replace(".", "").replace(",", "."))


with open("konto.csv", encoding="utf-8-sig", newline="") as datei:
    buchungen = list(csv.DictReader(datei, delimiter=";"))

bewegung = Decimal("0")
for buchung in buchungen:
    bewegung += zahl_aus_text(buchung["Betrag"])
print(f"Der Kontostand hat sich um {bewegung:+.2f} Euro geändert")

Im Kontoauszug steht vor manchen Beträgen ein Minus und vor anderen nichts. Ein Minus heißt, das Geld hat das Konto verlassen. Eine Überweisung, eine Lastschrift, eine Kartenzahlung. Ohne Vorzeichen kam es herein, das Gehalt zum Beispiel.

Wenn man alle Beträge zusammenzählt, weiß man also, um wie viel sich der Kontostand in dieser Zeit verändert hat. Mit dem + in :+.2f steht das Vorzeichen auch dann da, wenn es ein Plus ist.

Willst du wissen, wie viel hinausging, zählst du nur die Beträge unter null zusammen. Das Ergebnis schreibt man meistens ohne Minus hin, denn „Ausgaben: 2.404,29 Euro“ liest sich besser als minus Ausgaben.

Ein Betrag, der keiner ist

Ein Betrag, der keiner ist
from decimal import Decimal


def zahl_aus_text(text):
    """Macht aus einem deutschen Betrag wie "-1.234,56" ein Decimal."""
    return Decimal(text.replace(".", "").replace(",", "."))


try:
    print(zahl_aus_text("12,50 EUR"))
except ValueError:
    print("Kein Betrag")

Irgendwann steht in einer Spalte etwas, das kein Betrag ist. Jemand hat 12,50 EUR von Hand eingetragen, oder die Zeile ist leer. Mit Decimal klappt das nicht, aber der Fehler sieht anders aus als bei float() oder strptime. Das Programm endet mit decimal.InvalidOperation: [<class 'decimal.ConversionSyntax'>], obwohl daneben ein except ValueError steht.

InvalidOperation ist nämlich kein ValueError. Es ist ein Fehler aus dem Modul decimal mit eigener Art. Und welcher Text das Problem war, steht in der Meldung auch nicht.

Bleibt die Frage, was man mit einer kaputten Zeile macht. Überspringen liegt nahe, ein except mit continue darin, und schon läuft das Programm durch. Nur stimmt dann die Summe nicht, und niemand merkt es. Ein Kontoauszug, dem still zwölf Euro fehlen, ist schlechter als einer, der gar nicht erst durchläuft.

Deshalb soll sich so eine Zeile melden. zahl_aus_text fängt InvalidOperation ab und löst stattdessen einen ValueError aus, mit einer Meldung, in der der Text steht, so wie in Lektion 9.4. Ob das Programm dann aufhört oder nachfragt, wird an der Stelle entschieden, die die Funktion aufruft.

Was die Aufgabe will

Ein kurzer Kontoauszug, zwei Funktionen und drei Zeilen Auswertung. Der Zeitraum, was hereinkam und was hinausging. Dazu soll zahl_aus_text einen Betrag, der keiner ist, mit einem ValueError melden.

Zum Mitnehmen

Aus dem Text "-1.234,56" macht zahl_aus_text() ein Decimal, indem erst die Punkte verschwinden und dann das Komma zum Punkt wird. datum_aus_text() macht aus "03.09.2026" ein date. Ein Betrag mit Minus ist eine Ausgabe. Wenn Decimal einen Wert nicht lesen kann, kommt InvalidOperation, und das ist kein ValueError.

Jetzt du

Basis Konto, kostenlos

Zu dieser Lektion gehört eine Aufgabe. Du schreibst den Code selbst, und nach jedem Lauf sagt dir eine Prüfliste, was schon stimmt.

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 5 Beispielen zum Ausprobieren

    Steht hier, ohne Konto lesbar.

  • Aufgabe, dein Code läuft auf einem Server

    Öffnet sich mit dem Basis Konto.