Python-Kurs / CSV-Dateien mit DictReader und DictWriter verarbeiten

CSV, ausgeschrieben Comma Separated Values, speichert Datensätze und Felder als Text. Verwenden Sie das Modul csv zum Lesen von Trennzeichen und Anführungszeichen; prüfen und konvertieren Sie Zahlenfelder anschließend ausdrücklich, weil DictReader ihre Werte hier als Zeichenketten liefert.

CSV-Regeln statt einfachem split verwenden

Ein Name kann selbst ein Komma enthalten. In einer CSV-Datei lässt er sich dafür in Anführungszeichen einschließen; auch Zeilenumbrüche innerhalb eines Feldes sind möglich. split(",") versteht diese Struktur nicht. csv.reader rekonstruiert Felder nach dem gewählten Dialekt, und DictReader ordnet sie den Spaltennamen der Kopfzeile zu.

Öffnen Sie CSV-Dateien beim Lesen und Schreiben mit newline="", damit das CSV-Modul die Zeilenenden passend verarbeitet. Für UTF-8-Daten mit optionaler Byte Order Mark, kurz BOM, kann utf-8-sig beim Lesen die Anfangsmarkierung entfernen. Ohne diese Behandlung könnte die Markierung Teil des ersten Spaltennamens werden. Das macht beliebige andere Kodierungen jedoch nicht zu UTF-8.

Das Modul prüft nicht automatisch alle fachlichen Regeln. Legen Sie fest, welche Überschriften, Feldanzahlen, Zahlenformate und leeren Werte erlaubt sind. Die CSV-Referenz beschreibt Parser, Writer und DictReader.

Einen Namen mit Komma schreiben und Beträge summieren

Verwenden Sie einen separaten Übungsordner: Dieses vollständige Programm ersetzt expenses-demo.csv bei jedem Start. Speichern Sie es als csv_demo.py in UTF-8 und führen Sie python csv_demo.py mit dem Projektinterpreter aus. Unter macOS oder Ubuntu kann außerhalb einer aktivierten Umgebung python3 passen. Zusatzpakete und eine vorbereitete CSV-Datei sind nicht nötig, weil das Programm seine Testdatei selbst schreibt.

import csv
from pathlib import Path

path = Path("expenses-demo.csv")
with path.open("w", encoding="utf-8", newline="") as f:
    writer = csv.DictWriter(f, fieldnames=["name", "amount"])
    writer.writeheader()
    writer.writerows([{ "name": "lunch, team", "amount": 8000}, {"name": "bus", "amount": 2500}])
total = 0
with path.open(encoding="utf-8-sig", newline="") as f:
    reader = csv.DictReader(f)
    if reader.fieldnames != ["name", "amount"]:
        raise ValueError("unexpected header")
    for row in reader:
        total += int(row["amount"])
        print(row["name"])
print("total:", total)

Erwartete Ausgabe:

lunch, team
bus
total: 10500

DictWriter legt mit fieldnames die beiden Spalten fest und schreibt mit writeheader() die Kopfzeile. Der Name lunch, team wird wegen seines Kommas als ein Feld in Anführungszeichen geschrieben. Beim erneuten Einlesen bleibt dieser Name ein einzelner Wert. Die zwei Beträge werden mit int umgewandelt und ergeben 10500.

Öffnen Sie die Datei zusätzlich in einem Texteditor. Die erste Datenzeile enthält den Namen in Anführungszeichen; beim Lesen mit csv.reader hat sie trotzdem genau zwei Felder. Ein sichtbares Komma ist deshalb nicht immer ein Spaltentrenner. Die explizite Kodierung und der bewusst gewählte Schreibmodus entsprechen den Regeln der Übung zu Textdateien.

Überschriften, Beträge und Datensatzpositionen prüfen

Die gezeigte Headerprüfung verlangt genau ["name", "amount"], einschließlich Reihenfolge, Schreibweise und Anzahl. Eine umbenannte, zusätzliche oder doppelte Überschrift wird damit abgewiesen. Das ist eine bewusst strenge Schnittstelle. Wenn Ihre Anwendung andere Anordnungen akzeptieren soll, muss ihre Prüfregel ausdrücklich angepasst werden.

Die Prüfung der Überschrift ist noch keine vollständige Zeilenprüfung. Bei zusätzlichen Werten kann DictReader die überzähligen Werte unter dem Schlüssel None sammeln; bei fehlenden Feldern kann der fehlende Wert None sein. Das vorliegende Beispiel weist Zusatzfelder nicht ausdrücklich zurück. Vor einer produktiven Übernahme sollten Sie daher die tatsächliche Zeilenstruktur und Pflichtfelder prüfen, bevor Sie den Betrag konvertieren.

Ein leerer Betrag, "8,000" oder "8000 KRW" passt nicht unmittelbar zu int. Entfernen Sie nicht wahllos alle anderen Zeichen: Dadurch könnten falsche Werte unbemerkt normal aussehen. Vereinbaren Sie erlaubte Darstellung, Vorzeichen und Wertebereich. Dieses Beispiel prüft etwa keine Regel gegen negative Beträge; die Zahlenkonvertierung allein entscheidet das nicht.

Für Fehlerberichte kann enumerate(reader, start=2) eine Position der logischen Datensätze nach der Kopfzeile liefern. Enthält ein Feld einen Zeilenumbruch, entspricht diese Nummer nicht zwingend einer physischen Dateizeile. reader.line_num zählt die vom Parser gelesenen Quellzeilen und kann daher einen anderen Wert haben. Benennen Sie klar, welchen Bezug Ihre Fehlermeldung verwendet.

Ungültige Eingaben und erneute Ausführung getrennt testen

  1. Starten Sie das vollständige Programm zweimal. Die Ausgabe und die Anzahl der Datensätze bleiben gleich, weil w die Datei ersetzt.
  2. Für Tests einer nachträglich veränderten CSV-Datei kopieren Sie den Leseteil ab total = 0 in eine neue Datei csv_read_test.py. Ergänzen Sie davor import csv, from pathlib import Path und path = Path("expenses-demo.csv"). Dieser Test liest die bestehende Datei, ohne sie zuvor zu überschreiben.
  3. Ändern Sie in der CSV-Kopfzeile nur amount zu cost und starten Sie python csv_read_test.py. Erwarten Sie ValueError: unexpected header. Ein erneuter Start des vollständigen Schreib-und-Leseprogramms würde diese manuelle Änderung vorher wieder beseitigen und wäre kein solcher Eingabetest.
  4. Stellen Sie den Header wieder her und prüfen Sie einen leeren Betrag. Der unveränderte Lesecode scheitert bei der Konvertierung. Legen Sie für eine Erweiterung fest, ob Sie den Import abbrechen oder den verworfenen Datensatz mit Grund melden wollen; rechnen Sie nicht stillschweigend mit null weiter.
  5. Starten Sie schließlich das ursprüngliche vollständige Programm und vergleichen Sie alle drei Ausgabezeilen. Die Ausgangsdatei wird damit für diese Übung wiederhergestellt.

CSV legt nicht fest, wie eine Tabellenkalkulation die Feldinhalte interpretiert. Ein externer Wert mit führendem = kann je nach Importoption als Formel behandelt werden. Anführungszeichen regeln zunächst die CSV-Struktur und sind allein keine allgemeine Zusicherung einer Textinterpretation. Die LibreOffice-Hilfe zum Textimport unterscheidet beispielsweise die Auswertung von Formeln und die Behandlung zitierter Felder als Text. Stimmen Sie gemeinsame Exporte auf das Zielprogramm und die zulässigen Daten ab.