Formatierte Ausgabe



Wege die Ausgabe zu formatieren

Drucken im 16. Jahrhundert

In diesem Kapitel unseres Python-Tutorials werden wir uns intensiv mit den verschiedenen Methoden beschäftigen, mit denen man die Ausgaben formatieren bzw. formatierte Strings erzeugen kann. Wir stellen die verschiedenen Arten vor, aber wir empfehlen die format-Methode der Stringklasse zu benutzen, die sich kurz vor Ende des Kapitels befindet. Die format-Methode ist die bei weitem flexibelste.

Bisher hatten wir die print-Funktion auf zwei Arten benutzt, wenn wir beispielsweise zwei Werte ausgeben wollten:



Die alte Methode im Stil von printf und sprintf


Statt "alte" Methode sollten wir besser "veraltete" Methode sagen, da dieses Vorgehen keinen guten Python-Stil mehr darstellt.

Gibt es ein printf in Python? Das ist die brennende Frage für Python-Anfänger, die von C, Perl, Bash oder anderen Programmiersprachen kommen, die dieses Statement bzw. diese Funktion benutzen. Zu sagen, dass Python eine print-Funktion und keine printf-Funktion hat ist nur die eine Seite der Medaille. Also gibt es doch eine "printf"-Funktion in Python? Nein, aber die Funktionalität des "alten" printf wurde in anderer Form übernommen. Zu diesem Zweck wird der Modulo-Operator "%" von der String-Klasse überladen. Deshalb spricht man bei dem überladenen Operator "%" der String-Klasse auch häufig vom String-Modulo-Operator, obwohl es eigentlich wenig mit der eigentlich Modulo-Arithmetik zu tun hat. Manchmal wird er auch synonym als String-Modulus-Operator genannt. Ein weiterer Begriff, für diese Operation lautet "String-Interpolation", weil bei dieser Operation Werte, wie Integers, Floats usw., in den zu erzeugenden formatierten String eingefügt also interpoliert werden. Den mittels der String-Interpolation erzeugten formatierten String, kann man dann z.B. mittels print (also nicht printf) ausgeben. Aber man kann diesen formatierten String auch auf andere Art im Programm weiter verwenden, wie ihn zum Beispiel in eine Datenbank übertragen.
Seit Python 2.6 eingeführt worden ist, wird jedoch von der Python-Gemeinde empfohlen die String-Methode "format" stattdessen zu verwenden. Unglücklicherweise konnten man sich auch bei dem Design von Python3 nicht von der veralteten String-Interpolations-Methode trennen. Außerdem wird die veraltete Methode noch allzu häufig benutzt. Aus diesem Grunde gehen wir auch in unserem Tutorial ausgiebig darauf ein. Um fremden Python-Code verstehen zu können, der die String-Interpolations-Methode benutzt, ist es nötig den Mechanismus zu verstehen. Wahrscheinlich - oder hoffentlich - wird man sich jedoch bei der Weiterentwicklung von Python eines Tages von dieser Methode trennen.

Das folgende Diagramm verbildlicht die Arbeitsweise des String-Modulo-Operators:

Formatierte Ausgabe mittels String-Modulo-Operator an einem Beispiel

Auf der linken Seite des String-Modulo-Operators befindet sich der sogenannte Format-String und auf der rechten Seite steht ein Tupel mit den Werten, die in den Format-String interpoliert bzw. eingefügt werden sollen. Die Werte können Literale, Variablen oder beliebige arithmetische Ausdrücke sein.

Formatstring und Wertetupel

Der Formatstring enthält Platzhalter. In unserem Beispiel befinden sich zwei davon: "%5d" und "%8.2f".

Die allgemeine Syntax für diese Platzhalter lautet:

    %[flags][width][.precision]type 


Float-Format Schauen wir uns einmal die Platzhalter unseres Beispieles genauer an: Der zweite, also "%8.2f", ist eine Formatbeschreibung für eine Floatzahl. Wie auch alle anderen Platzhalter wird er durch ein "%"-Zeichen eingeleitet. Dieses wird von einer Zahl gefolgt, die die totale Anzahl der Zeichen angibt, mit der die Zahl ausgegeben werden soll. Diese Anzahl beinhaltet auch den Dezimalpunkt und alle Ziffern vor und nach dem Punkt. Unsere Floatzahl 59.058 muss also mit 8 Zeichen dargestellt werden. Der Dezimalanteil der Zahl ist auf 2 gesetzt, dies ist die Zahl hinter dem "." beim Platzhalter. Das bedeutet, dass die Anzahl der Nachkommastellen auf 2 gesetzt ist. Das letzte Zeichen im Platzhalt ist der Buchstabe "f". Wie sich leicht vermuten lässt, steht er für "float".

Schaut man sich die Ausgabe an, erkennt man, dass die Zahl "59.058" als " 59.06" ausgegeben wird. Man sieht auch, dass die Ausgabe nicht etwa nach zwei Stellen abgebrochen wird, sondern dass eine Rundung erfolgt. Außerdem werden von links drei Leerzeichen an die Zahl bei der Ausgabe angefügt.

Der erste Platzhalter "%5d" dient als Beschreibung für die erste Komponente unseres Tupels, d.h. die Ganzzahl (integer) 453. Diese Zahl soll mit 5 Zeichen ausgedruckt werden. Da 453 aber nur aus 3 Stellen besteht, werden der Zahl in der Ausgabe zwei Leerzeichen vorangestellt. Viele werden statt "%5d" einen Platzhalter der Art "%5i" erwartet haben, da es sich ja um eine Integer-Zahl handelt. Worin besteht der Unterschied? Ganz einfach: Es gibt keinen Unterschied zwischen "d" und "i". Beide werden zur Formatierung von Integers genutzt.

Die Vorteile bzw. die Schönheit der formatierten Ausgabe kann man nur ermessen, wenn man mehrere gleichermaßen formatierte Ausgaben ausgibt. Im folgenden Beispiel zeigen wir, wie es aussieht, wenn wir 5 Fließzahlen (floats) gleich formatiert mit dem Platzhalter "%6.2f" in verschiedenen Zeilen ausgeben:

Formatierte Floatzahlen in verschiedenen Zeilen


Platzhaltersymbol Bedeutung
d Vorzeichenbehaftete Ganzzahl (Integer, dezimal).
i Vorzeichenbehaftete Ganzzahl (Integer, dezimal).
o vorzeichenlose Ganzzahlen (oktal)
u vorzeichenlose Ganzzahlen (dezimal)
x vorzeichenlose Ganzzahlen (hexadezimal)
X vorzeichenlose Ganzzahlen (hexadezimal), Uppercase
e Fließkommazahl im Exponentialformat (in Kleinbuchstaben).
E Fließkommazahl im Exponentialformat (in Großbuchstaben).
f wie e
F wie E
g Wie "e", wenn der Exponent größer ist als -4 oder oder kleiner als die Präzision. Ansonsten wie "f"
G wie "E" und analog zu "g"
c ein Zeichen
s Eine Zeichenkette (String); beliebige Python-Objekte werden in String mittels der Methode str()) gewandelt.
r siehe s
% Es findet keine Argument-Konvertierung statt, es wird ein "%"-Zeichen ausgegeben.


Die folgenden Beispiele zeigen einige exemplarische Anwendungen der Konvertierungsmöglichkeiten der vorigen Tabelle:
>>> print("%10.3e"% (356.08977))
 3.561e+02
>>> print("%10.3E"% (356.08977))
 3.561E+02
>>> print("%10o"% (25))
        31
>>> print("%10.3o"% (25))
       031
>>> print("%10.5o"% (25))
     00031
>>> print("%5x"% (47))
   2f
>>> print("%5.4x"% (47))
 002f
>>> print("%5.4X"% (47))
 002F
>>> print("Ein Prozentzeichen: %% " % ())
Ein Prozentzeichen: % 
>>> 


Flag Bedeutung
# Wird dieses Zeichen mit o, x oder X benutzt, wird der jeweilige Wert mit dem entsprechenden folgenden Präfix: 0, 0o, 0O, 0x oder 0X
0 Das Ergebnis der Umwandlung wird mit Nullen aufgefüllt.
- Das Ergebnis der Umwandlung wird linksbündig ausgegeben.
  Falls kein Vorzeichen (beispielsweise ein Minuszeichen) ausgegeben wird, wird ein Leerzeichen vor den Wert gesetzt.
+ Das Ergebnis der Umwandlung wird mit einem Vorzeichen versehen ("+" oder "-"). Dieses Flag überschreibt ein "space"-Flag).


Beispiele:

>>> print("%#5X"% (47))
 0X2F
>>> print("%5X"% (47))
   2F
>>> print("%#5.4X"% (47))
0X002F
>>> print("%#5o"% (25))
 0o31
>>> print("%+d"% (42))
+42
>>> print("% d"% (42))
 42
>>> print("%+2d"% (42))
+42
>>> print("% 2d"% (42))
 42
>>> print("%2d"% (42))
42
Obwohl es so ausschauen mag, ist die Formatierung nicht Teil der Print-Funktion. Schaut man sich die vorigen Beispiele genauer an, sieht man, dass wir einen formatierten String an die Print-Funktion übergeben haben. Oder anders ausgedrückt: Wenn die String-Interpolation auf einen String angewendet wird, liefert sie einen String zurück. Dieser String wird dann an print übergeben. Dies bedeutet wiederum, dass wir die String-Interpolation auch hätten "zweistufig" anwenden können, d.h. wir hätten erst einen formatierten String erzeugt, diesen einer Variablen zugewiesen und diese Variable dann an print übergeben:
>>> s = "Preis: $ %8.2f"% (356.08977)
>>> print(s)
Preis: $   356.09
>>>


Der pythonische Weg: Die String-Methode "format"


Was die String-Methode format betrifft, ist die help-Funktion von Python nicht sehr hilfreich. Alles was sie uns sagt, ist dieses:

 |  format(...)
 |      S.format(*args, **kwargs) -> str
 |      
 |      Return a formatted version of S, using substitutions from args and kwargs.
 |      The substitutions are identified by braces ('{' and '}').
 |  


Die String-Methode "format" wurde mit Python 2.6 als Ersatz für die String-Interpolation eingeführt.

Ganz allgemein sieht "format" wie folgt aus:

template.format(p0, p1, ..., k0=v0, k1=v1, ...)

Der Format-String ist ein String, der ein oder mehrere Format-Codes innerhalb eines konstanten Textes enthält, d.h. Felder, die ersetzt werden sollen. Die zu "ersetzenden Felder" sind von geschweiften Klammern umgeben. Eine geschweifte Klammer und der von ihr umschlossene "Code" wird mit dem formatierten Wert aus dem korrespondierenden Argument ersetzt. Nach welchen Regeln dies zu erfolgen hat, werden wir im folgenden erläutern. Alles andere, was nicht von geschweiften Klammern umschlossen ist, wird wörtlich, also ohne Änderungen, ausgedruckt. Möchte man eine öffnende oder eine schließende geschweifte Klammer ausgeben, muss man diese verdoppeln, also "{{" oder "}}".

Es gibt zwei Arten von Argumenten für die format-Methode. Die Argumentenliste startet mit 0 oder mehr Positionsargumenten (p0, p1, ...), die von 0 oder mehr Schlüsselwortargumenten der Form name=value gefolgt werden können.

Ein Positionsparameter der format-Methode kann benutzt werden, indem man den Index des Parameters nach öffnenden geschweiften Klammer angibt, d.h. {0} für den ersten Parameter, {1} für den zweiten und so weiter. Der Index des Positionsparameter nach der öffnenden geschweiften Klammer kann von einem Doppelpunkt und einem Formatstring gefolgt werden, der dem des String-Interpolationsparameters ähnelt, den wir zu Beginn des Kapitels besprochen hatten, also zum Beispiel {0:5d}
Falls die Positionsparameter in der Reihenfolge benutzt werden, in der sie in der Parameterliste stehen, kann die Angabe des Indexes innerhalb der geschweiften Klammern entfallen, d.h. '{} {} {}' entspricht '{0} {1} {2}'. Um es nochmals klar zu stellen: Will man sie in einer anderen Reihenfolge benutzen, sind die Angaben der Indexpositionen dringend notwendig, wie z.B. hier '{2} {1} {0}'

Im folgenden Diagramm zeigen wir anhand eines Beispieles wie die Stringmethode "format" für zwei Parameter funktioniert:

Allgemeine Arbeitsweise der Stringmethode format für zwei Positionsparameter

Beispiele mit Positionsparametern:
>>> "Erstes Argument: {0}, zweites: {1}".format(47,11) 
'Erstes Argument: 47, zweites: 11'
>>> "Zweites Argument: {1}, erstes: {0}".format(47,11) 
'Zweites Argument: 11, erstes: 47'
>>> "Zweites Argument: {1:3d}, erstes: {0:7.2f}".format(47.42,11) 
'Zweites Argument:  11, erstes:   47.42'
>>> "Erstes Argument: {}, zweites: {}".format(47,11) 
'Erstes Argument: 47, zweites: 11'
>>> # Argumente können auch mehrmals verwendet werden:
... 
>>> "precisions: {0:6.2f} or {0:6.3f}".format(1.4148) 
'precions:   1.41 or  1.415'
>>> 


Im folgenden Beispiel demonstrieren wir, wie Schlüsselwortparameter mit der format-Methode benutzt werden können:
>>> "Artikel: {a:5d},  Preis: {p:8.2f}".format(a=453, p=59.058)
'Artikel:   453,  Preis:    59.06'
>>> 


Allgemeine Arbeitsweise der Stringmethode format für zwei Schlüsselwortparameter

Mit der format-Methode ist es auch möglich Daten links- und rechtsbündig auszugeben. Dazu müssen wir der Formatierungsanweisung ein "<" (linksbündig) oder ein ">" (rechtsbündig) voranstellen. Wir demonstrieren dies an den folgenden Beispielausgaben:

>>> "{0:<20s} {1:6.2f}".format('Spam & Eggs:', 6.99)
'Spam & Eggs:          6.99'
>>> "{0:>20s} {1:6.2f}".format('Spam & Ham:', 7.99)
'         Spam & Ham:  7.99'
>>>
>>> "{0:<20} {1:6.2f}".format('Spam '0'
If the width field is preceded by a zero ('0') character,  
sign-aware zero-padding for numeric types will be enabled.
>>> x = 378
>>> print("The value is {0:06d}".format(x))
The value is 000378
>>> x = -378
>>> print("The value is {0:06d}".format(x))
The value is -00378
& Ham:', 7.99) 'Spam & Ham: 7.99' >>> "{0:>20} {1:6.2f}".format('Spam & Ham:', 7.99) ' Spam & Ham: 7.99' >>>


Ausrichtungs-Option Bedeutung
'<' Das Feld wird linksbündig innerhalb des vorhandenen Raumes ausgegeben. Strings werden standardmäßig linksbündig ausgegeben.
'>' Das Feld wird rechtsbündig innerhalb des vorhandenen Raumes ausgegeben. Numerische Werte werden standardmäßig rechtsbündig ausgegeben.
'0' Wenn man das Formatfeld mit einer führenden Null ('0') versieht, erfolgt ein Auffüllen mit Nullen unter Beachtung eines möglichen Vorzeichens.
>>> x = 378
>>> print("The value is {0:06d}".format(x))
The value is 000378
>>> x = -378
>>> print("The value is {0:06d}".format(x))
The value is -00378
',' Mit dieser Option erhält man Tausender Gruppierungen, die mit Komma getrennt sind:
>>> print("The value is {:,}".format(x))
The value is 78,962,324,245
>>> print("The value is {0:6,d}".format(x))
The value is 5,897,653,423
>>> x = 5897653423.89676
>>> print("The value is {0:12,.3f}".format(x))
The value is 5,897,653,423.897
'=' Die Auffüllzeichen (padding characters) werden zwischen Vorzeichen, falls ein Vorzeichen ausgegeben wird und dem eigentlichen Beginn der Ziffern einer Zahl eingeführt. Damit können Felder der Art "+000000120" ausgegeben werden. Diese Ausrichtungsoption kann nur auf numerische Werte angewendet werden.
'^' Ein Feld wird zentriert innerhalb des zur Verfügung stehenden Raumes ausgegeben.

Wenn keine minimale Feldlänge angegeben wird, entspricht die Feldlänge immer der Länge der Daten, die ein Feld enthält. In diesen Fällen haben die Ausrichtungsoptionen keine Bedeutung.


Zusätzlich können wir noch die Ausgabe mittels der sign-Option beeinflussen. Diese Optionen sind nur für numerische Werte gültig:

sign-Option Bedeutung
'+' Es soll immer ein Vorzeichen ausgegeben werden, also unabhängig davon, ob es sich um eine positive oder negative Zahl handelt.
'-' Ein Vorzeichen soll nur bei negativen Zahlen verwendet werden.
space Statt eines "+"-Zeichens wird bei positiven Zahlen ein Leerzeichen " " vorangestellt. Bei negativen Zahlen ein Minus-Zeichen "-".


Benutzung von Dictionarys beim Aufruf der "format"-Methode

In den vorigen Kapitel haben wir gesehen, dass wir zwei Möglichkeiten haben Werte mit "format" zu formatieren: Im zweiten Fall könnten wir auch ein Dictionary verwenden, wie wir im folgenden Code sehen können:
>>> data = dict(province="Ontario",capital="Toronto")
>>> data
{'province': 'Ontario', 'capital': 'Toronto'}
>>> print("The capital of {province} is {capital}".format(**data))
The capital of Ontario is Toronto
>>> 
Das doppelte Sternchen ("*") vor data wandelt data automatisch in die Form 'province="Ontario",capital="Toronto"'. Schauen wir uns das folgende Python-Programm an:
capital_country = {"Vereinigte Staaten" : "Washington", 
                   "US" : "Washington", 
                   "Kanada" : "Ottawa",
                   "Deutschland": "Berlin",
                   "Frankreich" : "Paris",
                   "England" : "London",
                   "Großbritannien" : "London",
                   "Schweiz" : "Bern",
                   "Österreich" : "Wien",
                   "Niederlande" : "Amsterdam"}

print("Länder und Ihre Hauptstädte:")
for c in capital_country:
    print("{country}: {capital}".format(country=c, capital=capital_country[c]))
Wenn wir dieses Programm starten, erhalten wir die folgende Ausgabe:
$ python3 country_capitals.py 
Länder und Ihre Hauptstädte:
Schweiz: Bern
Großbritannien: London
England: London
US: Washington
Frankreich: Paris
Kanada: Ottawa
Niederlande: Amsterdam
Deutschland: Berlin
Österreich: Wien
Vereinigte Staaten: Washington
Das vorige Programm können wir so umschreiben, dass im Aufruf der format-Methode das Dictionary direkt verwendet wird.

capital_country = {"Vereinigte Staaten" : "Washington", 
                   "US" : "Washington", 
                   "Kanada" : "Ottawa",
                   "Deutschland": "Berlin",
                   "Frankreich" : "Paris",
                   "England" : "London",
                   "Großbritannien" : "London",
                   "Schweiz" : "Bern",
                   "Österreich" : "Wien",
                   "Niederlande" : "Amsterdam"}

print("Countries and their capitals:")
for c in capital_country:
    format_string = c + ": {" + c + "}" 
    print(format_string.format(**capital_country))


Der Ausdruck ist gleich wie beim ersten Programm.

Benutzung von lokalen Variablen in "format"

"locals" ist eine Funktion, die ein Dictionary mit den lokal definierten Namen und ihren aktuellen Werten zurückliefert. Die Variablen sind die Schlüssel dieses Dictionary und die Werte zu den Schlüsseln entsprechen den Werten der Variablen:
>>> a = 42
>>> b = 47
>>> def f(): return 42
... 
>>> locals()
{'a': 42, 'b': 47, 'f': <function f at 0xb718ca6c>, '__builtins__': <module 'builtins' (built-in)>, '__package__': None, '__name__': '__main__', '__doc__': None}
>>> 
Das Dictionary, was von locals() zurückgeliegert wird, kann als Parameter für die format-Methode genutzt werden. Dadurch ist es möglich im Format-String lokale Variablen zu verwenden.

Im folgenden Beispiel benutzen wir die lokalen Variablen a, b und f:
>>> print("a={a}, b={b} and f={f}".format(**locals()))
a=42, b=47 and f=<function f at 0xb718ca6c>


Weitere String-Methoden zum Formatieren

Die String-Klasse enthält weitere Methoden, die man auch zu Formatierungszwecken nutzen kann: ljust, rjust, center und zfill

Falls S ein String ist, können wir die vier Methoden wie folgt erklären: