mitmario.dev

Ein Paket im Einsatz: tabulate

Python Sandbox 3 Min Lesezeit 4 BeispieleLektion 2 von 5

„Kaffee gemahlen“ hat fünfzehn Zeichen. Auf dem Kassenbon hat die Spalte für den Namen aber nur zehn, die für den Preis acht. Das sah ordentlich aus, solange jeder Name hineingepasst hat.

Der Bon von Hand

Der Bon von Hand
posten = [
    ("Brot", 2.49),
    ("Milch", 2.38),
    ("Eier", 3.20),
    ("Kaffee gemahlen", 6.99),
]

for name, preis in posten:
    print(f"{name:<10}{preis:>8.2f}")
print("-" * 18)

Mit dem gemahlenen Kaffee ist es vorbei. Sein Name ist länger als zehn Zeichen. :<10 schneidet aber nichts ab, sondern schiebt den Preis nach rechts, und schon ist die Spalte keine mehr.

Von Hand ließe sich das reparieren. Du suchst den längsten Namen und rechnest daraus die Breite aus, für die Linie machst du dasselbe und bei einer dritten Spalte alles noch einmal. Das ist die Sorte Arbeit, die einem ein Paket abnimmt. Mehr macht tabulate auch nicht.

Derselbe Bon mit tabulate

Derselbe Bon mit tabulate
from tabulate import tabulate

posten = [
    ("Brot", 2.49),
    ("Milch", 2.38),
    ("Eier", 3.20),
    ("Kaffee gemahlen", 6.99),
]

print(tabulate(posten, headers=["Artikel", "Preis"]))

tabulate bekommt eine Liste von Zeilen und unter headers die Überschriften. Jede Zeile ist eine Liste oder ein Tupel mit einem Wert je Spalte. Zurück kommt ein Text, und den gibt print aus.

Jede Spalte ist so breit wie ihr längster Eintrag. Text steht links, Zahlen stehen rechts und am Punkt untereinander. Ein noch längerer Name ändert daran nichts, dann wird die Spalte eben breiter.

Nur die Eier stimmen nicht. Da steht 3.2 statt 3.20, so ist das Paket eingestellt. tabulate schreibt eine Kommazahl von sich aus so kurz wie möglich, und für Messwerte ist das in Ordnung. Für Geld nicht. Aus 58,00 Euro würde sogar eine nackte 58.

Die Standardeinstellung eines Pakets ist die, die seinem Autor am sinnvollsten schien. Das muss nicht die sein, die du brauchst. Bevor jemand anderes das Ergebnis zu sehen bekommt, lohnt sich deshalb ein Blick in die Dokumentation. Die von tabulate steht auf seiner Seite bei pypi.org.

Nachkommastellen und Aussehen

Mit Rahmen und zwei Stellen
from tabulate import tabulate

posten = [
    ("Brot", 2.49),
    ("Milch", 2.38),
    ("Eier", 3.20),
    ("Kaffee gemahlen", 6.99),
]

print(tabulate(posten, headers=["Artikel", "Preis"], floatfmt=".2f", tablefmt="rounded_outline"))

Mit floatfmt=".2f" bekommt jede Kommazahl zwei Stellen. Die Angabe ist dieselbe wie in einem f-String.

Über tablefmt stellst du das Aussehen ein. Ohne die Angabe steht die Tabelle da wie oben, mit einer Linie unter den Spaltennamen. "rounded_outline" zieht einen Rahmen mit runden Ecken darum, "grid" einen aus Plus- und Minuszeichen mit einer Linie zwischen allen Zeilen. Und mit "github" kommt die Tabelle in einer Form heraus, die viele Notiz-Programme und Wikis als Tabelle anzeigen.

Ausrechnen tut tabulate nichts. Eine Summe ist eine Zeile wie jede andere, die hängst du selbst an die Liste, bevor die Tabelle entsteht. Ein deutsches Komma gibt es auch nicht, die Zahlen stehen mit Punkt da, wie überall in Python. Im Terminal stört das kaum. Für einen Bericht, den jemand anderes liest, kommt in Lektion 13.4 die Excel-Datei.

Ein Dictionary ist keine Tabelle

Ein Dictionary statt Zeilen
from tabulate import tabulate

preise = {"Brot": 2.49, "Milch": 1.19, "Kaffee gemahlen": 6.99}

print(tabulate(preise, headers=["Artikel", "Preis"]))

Preise stehen oft in einem Dictionary, und da liegt es nahe, das direkt hineinzugeben. Heraus kommt ein langer Traceback mit zwei Fehlern. Zwischen ihnen steht During handling of the above exception, another exception occurred. Während der erste Fehler behandelt wurde, kam also noch ein zweiter dazu.

Der erste passiert im Code von tabulate. Der Pfad mit /opt/lern-mods/ ist der Ort, an dem das Paket hier liegt. Den zweiten löst das Paket selbst aus, als Erklärung hinterher: To build a table python-tabulate requires two-dimensional data like a list of lists or similar. Eine Tabelle braucht Daten in zwei Richtungen, Zeilen und Spalten.

Ein Dictionary liest tabulate anders, als man denkt. Jeder Eintrag wird eine ganze Spalte, und ihr Inhalt soll der Wert sein. Eine einzelne Zahl ist aber keine Spalte. Mit preise.items() werden daraus Paare aus Schlüssel und Wert, ein Paar je Zeile, und so will tabulate es haben.

Was die Aufgabe will

Die Monatsübersicht aus dem Kontoauszug, diesmal als Tabelle. Was je Kategorie ausgegeben wurde und wie viele Buchungen es waren, rechnet das Programm schon aus und legt es in zwei Dictionaries ab. Es fehlen nur noch die Zeilen für tabulate und die Tabelle selbst.

Zum Mitnehmen

tabulate(zeilen, headers=[...]) baut aus einer Liste von Zeilen eine Tabelle, und jede Spalte wird so breit wie ihr längster Eintrag. Bei Geld gehört floatfmt=".2f" dazu, damit die Nullen hinter dem Punkt bleiben. tablefmt bestimmt das Aussehen, und aus einem Dictionary werden erst mit items() Zeilen.

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

    Steht hier, ohne Konto lesbar.

  • Aufgabe, dein Code läuft auf einem Server

    Öffnet sich mit dem Basis Konto.