HOWTO zu Formatierter Ausgabe  in Python

(C) 2019-2025 T.Birnthaler/H.Gottschalk <howtos(at)ostc.de>
              OSTC Open Source Training and Consulting GmbH
              www.ostc.de

Dieses Dokument beschreibt die Formatierung von Strings in Python, die auf 3
verschiedene Arten möglich ist (C-printf-Stil, Python-Stil 1 und Python-Stil
2).

Inhaltsverzeichnis

1) Dokumentation
2) Einführung
3) Python Stil 2
3.1) Beispiele zum Python Stil 2
4) Python Stil 1
4.1) Beispiele zum Python Stil 1
4.2) Built-in Funktion "format"
5) C-printf-Stil
5.1) Beispiele zum C-printf-Stil

1) Dokumentation   (Toc)

  Hilfreiche Seite mit Formatierung-Beispielen
  Kochbuch mit Formatierung-Rezepten
  Cheatsheet Python Formatting
  format()-Function
  printf-style String Formatting
  printf-style String Formatting
  String Methods
  Format Specification Mini-Language
  Format String Syntax F"..."
  Custom String Formatting
  Formatter Class
  Formatted String Literals
  Template Strings (4. Methode)

2) Einführung   (Toc)

In Python gibt es 3 Arten, FORMATIERTE Zeichenketten bestehend aus FESTEN
Textteilen und VARIABLEN Datenteilen zu erzeugen. Alle 3 beruhen auf dem
Prinzip, in eine SCHABLONE/ein TEMPLATE (= FORMAT-String bestehend aus TEXT +
PLATZHALTERN) WERTE im passenden Format einzubauen und das Ergebnis als STRING
zurückzugeben:

  +------+-----------------+---------------------+--------+-------------------+
  | Stil | Bezeichnung     | Syntax              | Platzh.| Eigenschaften     |
  +------+-----------------+---------------------+--------+-------------------+
  | Py2  | Format-String   | F"FMT+WERTE"        | {...}  | MOD HOCH KOMP NAM |
  | Py1  | Format-Funktion | "FMT".format(WERTE) | {...}  | MOD MITT LANG P+N |
  |  C   | Analog C-printf | "FMT" % (WERTE)     | %...   | ALT NIED LANG POS |
  +------+-----------------+---------------------+--------+-------------------+
   (MOD=modern, HOCH/MITT/NIED=Flexibilität, KOMP=kompakt, NAM=Name,
    P+N=Position+Name, POS=Position, FMT=Format)

Hier ein Beispiel für alle 3 Stile mit dem gleichen Ergebnis: Folgende 3 Werte

  z = 5678      # Ganzzahl
  k = 3.1462    # Fließkommazahl
  t = "hallo"   # String

werden per Platzhalter mit passendem Formattyp (d=decimal, f=float, s=string)
in einen String eingebaut:

  print(F"Zahl {z:6d}, Wert {k:6.2f}, Text {t:10s}")                       # Py2
  print( "Zahl {0:6d}, Wert {1:6.2f}, Text {2:10s}".format(z, k, t))       # Py1
  print( "Zahl {a:6d}, Wert {b:6.2f}, Text {c:10s}".format(a=z, b=k, c=t)) # Py1
  print( "Zahl %6d, Wert %6.2f, Text %-10s" % (z, k, t))                   # C

Es ergibt sich jeweils der gleiche Ergebnisstring (Zahlen rechtsbündig, String
linksbündig):

  "Zahl   5678, Wert   3.15, Text hallo     "
        ------       ------       ----------
          6d          6.2f         -10s/10s

Die PLATZHALTER werden also per {} oder % dargestellt, der TYP-BUCHSTABE am
Ende eines Platzhalters legt den DATENTYP des einzufüllenden Werts fest (Python
prüft dies auch). Der WERT zu einem Platzhalter wird festgelegt durch:

  1)  Variablenname im Platzhalter {}  (Umordnung + Mehrfachverw. möglich)
  2a) Position im .format()-Aufruf     (Umordnung + Mehrfachverw. möglich)
  2b) Name im .format()-Aufruf         (Umordnung + Mehrfachverw. möglich)
  3)  Position im Tupel nach %-Zeichen (KEINE Umordnung + Mehrfachverwendung)

Folgende TYP-BUCHSTABEN sind verfügbar (allen 3 Stilen gemeinsam, * = üblich):

  +-----+-------------+--------------------------------------------------------+
  | Typ | Name        | Bedeutung                                              |
  +-----+-------------+--------------------------------------------------------+
  |  s  | string     *| Zeichenkette (DEFAULT, weglassbar)                     | *
  | (r) | repr        | Repräsentation (NUR im C-Stil, sonst Konvertierung r!) |
  |  c  | character   | Zeichen per Code-Nummer (Unicode)                      |
  +-----+-------------+--------------------------------------------------------+
  |  d  | decimal    *| Ganzzahl im Dezimalformat                              | *
  | (i) | integer     | Ganzzahl im Dezimalformat (NUR im C-Stil, analog "d")  |
  |  n  | number      | Ganzzahl analog "d" (aber Trennzeichen gemäß locale)   |
  +-----+-------------+--------------------------------------------------------+
  | (b) | binary      | Ganzzahl im Binärformat (Ziffern 0/1, NICHT im C-Stil) |
  |  o  | octal       | Ganzzahl im Oktalformat (Ziffern 0-7)                  |
  | x X | hexadecimal | Ganzzahl im Hexadezimalformat (x=abcdef, X=ABCDEF)     |
  +-----+-------------+--------------------------------------------------------+
  | f F | float      *| Fließkommaz. im Festpunktformat (inf/nan <-> INF/NAN)  | *
  | e E | exponent    | Fließkommaz. im Exponentialformat mit e/E-Zeichen      |
  | g G | general     | "f/F" oder "e/E" je nachdem wo mehr Ziffern darstellbar|
  |  n  | number      | Fließkommaz. analog "g" (Trennzeichen gemäß locale)    |
  +-----+-------------+--------------------------------------------------------+
  | (%) | percent     | Fließkommazahl analog "f" * 100 + %-Zeichen danach     |
  |     |             | (NICHT im C-Stil)                                      |
  +-----+-------------+--------------------------------------------------------+

Die Typinformation kann um weitere Angaben ergänzt werden, welche die genaue
FORM der Ausgabe kontrollieren:

  * Minimale+maximale Breite (auffüllen/runden/abschneiden)
  * Füllzeichen              (Standard: Leerzeichen)
  * Ausrichtung              (Standard: Zahlen rechtsbündig, Strings linksbündig)
  * Anzahl Nachkommastellen  (Standard: 6)
  * Tausender-Komma          (Standard: keines)
  * Konvertierung            (Standard: keine)
  * Weitere Eigenschaften

Weitere Besonderheiten sind:

* Ist ein Wert BREITER als in der zugehörigen Format-Angabe festgelegt, dann
  "SPRENGT" er die vorgegebene Breite, d.h. Zahlen und Strings werden nicht
  abgeschnitten (außer Strings am rechten Rand bei Angabe der Maximal-Breite).

    z = 123456789   # Ganzzahl
    k = 98765.432   # Fließkommazahl
    t = "hallowelt" # String

  mit Formatierung::

    print(F"Zahl {z:6d}, Wert {k:6.2f}, Text {t:5}")                       # Py2
    print( "Zahl {0:6d}, Wert {1:6.2f}, Text {2:5}".format(z, k, t))       # Py1
    print( "Zahl {a:6d}, Wert {b:6.2f}, Text {c:5}".format(a=z, b=k, c=t)) # Py1
    print( "Zahl %6d, Wert %6.2f, Text %-5" % (z, k, t))                   # C

  ergibt:

  "Zahl 123456789, Wert 98765.43, Text hallowelt"
        ------XXX       ------XX       -----XXXX         # XXX = gesprengt
          6d            6.2f           -5s/5s

* Sollen die Platzhalter-Zeichen "{" und "}" bzw. "%" selbst im Text stehen,
  dann sind sie jeweils zu VERDOPPELN:

    F"{{ {text} }}"           # --> "{ hallo }"
    "%d%% (Prozent)" % 19     # --> "19% (Prozent)"

* Text-Literale sind per '...' in "..." einschachtelbar (und umgekehrt):

    F"{'TE'+'XT':^10s}"       # --> "   TEXT   "
    F'{"TE"+"XT":^10s}'       # --> "   TEXT   "

* Der Platzhalter "{VAR}" (Stil 2) oder "{}" (Stil 1) fügt Variablenwert
  TYP-UNABHÄNGIG in passender Breite in den Text ein:

    F"Z: {zahl}, W: {wert}, T: {text}"   # --> "Z: 5678, W: 3.15, T: hallo"

* Der Platzhalter "{VAR=}" gibt Variablen-NAME + -WERT mit "=" dazwischen aus
  (zu Debug-Zwecken nützlich):

    F"{zahl=} {wert=} {text=}"   # --> "zahl=5678 wert=3.15 text=hallo"

3) Python Stil 2   (Toc)

Die Formatangabe (Format String Syntax) hat folgende Form (ohne Zwischenraum,
EXPR ist ein beliebiger Ausdruck, dessen Wert eingefüllt wird, !CONV und :SPEC
sind optional):

  "{" EXPR ":"}"
  "{" EXPR ":" SPEC "}"
  "{" EXPR "!" CONV ":" SPEC "}"

Bedeutung:

  +------+----------------------------------------------------------+
  | EXPR | Zu formatiertendes Objekt (Variablenname/Rechenausdruck) |
  | CONV | Festlegung der Konvertierung gemäß folgender Tabelle     |
  | SPEC | Festlegung der Formatierung gemäß folgender Tabelle      |
  +------+----------------------------------------------------------+

CONV konvertiert den Wert gemäß folgender Regeln:

  +----+---------+--------------------------------------------+
  | !a | ascii   | Funktion ascii() auf Wert anwenden         |
  | !r | repr    | Funktion repr() auf Wert anwenden          |
  | !s | string  | Funktion str() auf Wert anwenden (Default) |
  +----+---------+--------------------------------------------+

Die Format Specification Mini-Language SPEC legt die Formatierung des Wertes
über folgende Komponenten fest (diese Reihenfolge, kein Zwischenraum, alle
Elemente sind optional außer FILL erfordert gleichzeitig ALIGN):

  [[FILL] ALIGN] [SIGN] [#] [0] [WIDTH] [GRPOPT] [.PREC] [TYPE]

Bedeutung:

  +--------+------------------------------------------------------------------+
  | FILL   | Füllzeichen (Standard Leerzeichen " ", "}" nicht erlaubt         |
  | ALIGN  | "<" (left), ">" (right), "^" (center), "=" (zw. Vorz. und Zahl)  |
  | SIGN   | "+" ("+"/"-" erzwingen), "-" ("-" falls nötig), " " (" "/"-")    |
  | #      | Setzt "0b", "0o" oder "0x" vor Ganzzahlen (abhängig von TYPE)    |
  | 0      | Zahlen mit "0" auffüllen (FILL ist allgemeiner)                  |
  | WIDTH  | Minimale Breite (mit " ", "0" oder FILL aufgefüllt)              |
  | GRPOPT | "_" oder "," erzeugt Tausendertrenner-Zeichen (3er-Gruppen)      |
  | .PREC  | Maximale Breite bei Strings / Anzahl Nachkommastellen bei Zahlen |
  | TYPE   | "bcdeEfFgGnosxX%" analog obiger Typtabelle ("i" nur im C-Stil)   |
  +--------+------------------------------------------------------------------+

Beispiel:

  F"Zahl {z:6d}, Wert {k:6.2f}, Text {t:10s}")               # Variable
  F"Zahl {z*5+2:6d}, Wert {k/5.0:6.2f}, Text {t+'X':10s}")   # Rechenausdruck

Ergibt:

  "Zahl   5678, Wert   3.14, Text hallo     "
  "Zahl  28392, Wert   0.63, Text halloX    "
        ------       ------       ----------
          6d          6.2f           10s

ACHTUNG: Im Python Stil 2 lassen sich mit weiteren (eingeschachtelten) Klammern
{...} beliebige Teile der Format-Angabe per Variable Rechenausdruck füllen
(Makro-Logik):

  breite = 10
  nkst   = 3
  typ    = "d"
  ausr   = "<"
  F"Zahl {z:{ausr}{breite}{typ}}, Wert {k:{breite}.{nkst}f}, Text {t:{breite}s}"

Ergibt:

  "Zahl 5678      , Wert      3.142, Text hallo     "
        ----------       ----------       ----------
           10d              10.3f            10s

3.1) Beispiele zum Python Stil 2   (Toc)

  zahl = 1234567.89          #     |123456789012| (Ausgabespalten)
                             #
  F"{zahl:+12.1f}"           # --> '  +1234567.9'
  F"{zahl:+012.1f}"          # --> '+001234567.9'
  F"{zahl:<+12.1f}"          # --> '+1234567.9  '
  F"{zahl:<-12.1f}"          # --> '1234567.9   '
  F"{zahl:< 12.1f}"          # --> ' 1234567.9  '
  F"{zahl:<12.1f}"           # --> '1234567.9   '
  F"{zahl:<012.1f}"          # --> '1234567.9000'
  F"{zahl:012.1f}"           # --> '0001234567.9'
  F"{zahl:f}"                # --> '1234567.890000'   # Std: 6 Nachkommastellen
                             #
  F"{zahl:*=+12.1f}"         # --> '+**1234567.9'
  F"{zahl:*>+12.1f}"         # --> '** 1234567.9'
  F"{zahl:-012.1f}"          # --> '0001234567.9'
  F"{zahl:,.2f}"             # --> '1,234,567.89'
  F"{zahl:_.2f}"             # --> '1_234_567.89'
  F"{zahl:12,.2f}"           # --> '1,234,567.89'
  F"{zahl:12_.2f}"           # --> '1_234_567.89'
                             #
  text = "hallowelt"         #     |123456789012| (Ausgabespalten)
                             #
  F"{text:s}"                # --> 'hallowelt'
  F"{text:12s}"              # --> 'hallowelt   '
  F"{text:<12s}"             # --> 'hallowelt   '
  F"{text:^12s}"             # --> '  hallowelt '
  F"{text:>12s}"             # --> '   hallowelt'
  F"{text:012s}"             # --> 'hallowelt000'
  F"{text:12.12s}"           # --> 'hallowelt   '
  F"{text:6.6s}"             # --> 'hallow'
  F"{text:12.6s}"            # --> 'hallow      '

4) Python Stil 1   (Toc)

Die Formatangabe (Format String Syntax) hat folgende Form (ohne Zwischenraum,
INDEX ist eine Positionsnummer (startet mit 0) oder ein Name, dessen Wert
eingefüllt wird, !CONV und :SPEC sind optional):

  "{}"
  "{" INDEX/NAME "}"
  "{" INDEX/NAME ":" SPEC "}"
  "{" INDEX/NAME "!" CONV ":" SPEC "}"

Bedeutung:

  +-------+----------------------------------------------------------+
  | INDEX | Position in Werte-Liste des .format(WERTE)-Aufrufs       |
  | NAME  | Name des Wertes in .format(NAME=WERT, ...)-Aufruf        |
  | CONV  | Festlegung der Konvertierung gemäß Tabelle weiter unten  |
  | SPEC  | Festlegung der Formatierung gemäß Tabelle weiter unten   |
  +-------+----------------------------------------------------------+

Im Python-Stil 1 steht im Platzhalter vor einem ":" ein INDEX (startet mit 0),
welche die POSITION in der Werte-Liste im .format(WERTE)-Aufruf angibt
(Reihenfolge der Nummern beliebig, gleiche Nummer mehrfach erlaubt). Ohne Index
werden die Werte von links nach rechts in die Platzhalter eingefüllt (":" ist
trotzdem notwendig!). Alternativ sind auch NAMEN für die format()-Parameter
vergebbar, die vor dem ":" als Referenz verwendbar sind:

  "Zahl {:6d}, Wert {:6.2f}, Text {:10s}".format(z, k, t)          # Index automatisch
  "Zahl {0:6d}, Wert {1:6.2f}, Text {2:10s}".format(z, k, t)       # Index explizit
  "Zahl {a:6d}, Wert {b:6.2f}, Text {c:10s}".format(a=z, b=k, c=t) # Name

Ergibt:

  "Zahl   5678, Wert   3.14, Text hallo     "
  "Zahl   5678, Wert   3.14, Text hallo     "
  "Zahl   5678, Wert   3.14, Text hallo     "
        ------       ------       ----------
          6d          6.2f           10s

Im einfachsten Fall genügt "{}" als Platzhalter, diese werden von links nach
rechts mit den Werten in .format(...) in der NOTWENDIGEN Breite gefüllt (eine
Typprüfung findet hier nicht statt):

  "Zahl {}, Wert {}, Text {}".format(z, k, t)

Ergibt:

  "Zahl 5678, Wert 3.1415, Text hallo"
        ----       ------       -----

4.1) Beispiele zum Python Stil 1   (Toc)

  zahl = 1234567.89          #     |123456789012| (Ausgabespalten)
                             #
  "{:+12.1f}".format(zahl)   # --> '  +1234567.9'
  "{:+012.1f}".format(zahl)  # --> '+001234567.9'
  "{:<+12.1f}".format(zahl)  # --> '+1234567.9  '
  "{:<-12.1f}".format(zahl)  # --> '1234567.9   '
  "{:< 12.1f}".format(zahl)  # --> ' 1234567.9  '
  "{:<12.1f}".format(zahl)   # --> '1234567.9   '
  "{:<012.1f}".format(zahl)  # --> '1234567.9000'
  "{:012.1f}".format(zahl)   # --> '0001234567.9'
  "{:f}".format(zahl)        # --> '1234567.890000'   # Std: 6       Nachkommastellen
                             #
  "{:*=+12.1f}".format(zahl) # --> '+**1234567.9'
  "{:*> 12.1f}".format(zahl) # --> '** 1234567.9'
  "{:-012.1f}".format(zahl)  # --> '0001234567.9'
  "{:,.2f}".format(zahl)     # --> '1,234,567.89'
  "{:_.2f}".format(zahl)     # --> '1_234_567.89'
  "{:12,.2f}".format(zahl)   # --> '1,234,567.89'
  "{:12_.2f}".format(zahl)   # --> '1_234_567.89'

  text = "hallowelt"         #     |123456789012| (Ausgabespalten)
                             #
  "{:s}".format(text)        # --> 'hallowelt'
  "{:12s}".format(text)      # --> 'hallowelt   '
  "{:<12s}".format(text)     # --> 'hallowelt   '
  "{:^12s}".format(text)     # --> '  hallowelt '
  "{:>12s}".format(text)     # --> '   hallowelt'
  "{:012s}".format(text)     # --> 'hallowelt000'
  "{:12.12s}".format(text)   # --> 'hallowelt   '
  "{:6.6s}".format(text)     # --> 'hallow'
  "{:12.6s}".format(text)    # --> 'hallow      '

4.2) Built-in Funktion "format"   (Toc)

HINWEIS: Ein EINZELNER Wert kann durch die Built-in Funktion "format()" gemäß
obiger Syntax formatiert werden (geschweifte Klammern "{}" sind wegzulassen):

  format(z, "6d")     # --> "  5678"
  format(k, "6.2f")   # --> "  3.14"
  format(t, "10s")    # --> "hallo     "

Die Built-in Funktion "format(VALUE, FMTSPEC)" ruft folgende Funktion auf:

  type(VALUE).__format__(VALUE, FMTSPEC)

5) C-printf-Stil   (Toc)

Formatelemente beginnen mit dem Zeichen "%" und enden mit einem Typbuchstaben
TYPE (ohne Zwischenraum, das %-Zeichen und TYPE müssen angegeben werden, die
restlichen Elemente dürfen fehlen).

  % [(MAP)] [FLAGS] [WIDTH] [.PREC] [LENMOD] TYPE

Bedeutung:

  +--------+------------------------------------------------------------------+
  | (MAP)  | Dictionary Key (zugehöriger Wert muss ein Dictionary sein,       |
  |        | (KEY) in Klammern greift auf zugehörigen VALUE in Dictionary zu) |
  | FLAGS  | "#" Alternative Form ("0o", "0x", "0X")                          |
  |        | "0" Mit "0" statt Leerzeichen auffüllen                          |
  |        | "-" Linksbündig (statt rechtsbündig)                             |
  |        | " " Vorzeichen "+" als Leerzeichen ausgeben                      |
  |        | "+" Vorzeichen "+" als "+" ausgeben                              |
  | WIDTH  | Minimale Breite (mit " " oder "0" aufgefüllt)                    |
  | .PREC  | Maximale Breite bei Strings / Anzahl Nachkommastellen bei Zahlen |
  | LENMOD | "hlL" (short/long/long long, in Python irrelevant)               |
  | TYPE   | "bcdeEfFgiGnosxX%" analog obiger Typtabelle ("i" nur im C-Stil)  |
  +--------+------------------------------------------------------------------+

5.1) Beispiele zum C-printf-Stil   (Toc)

  zahl = 1234567.89   #     |123456789012| (Ausgabespalten)
                      #
  "%+12.1f"  % zahl   # --> '  +1234567.9'
  "%+012.1f" % zahl   # --> '+001234567.9'
  "%-+12.1f" % zahl   # --> '+1234567.9  '
  "%--12.1f" % zahl   # --> '1234567.9   '
  "%- 12.1f" % zahl   # --> ' 1234567.9  '
  "%-12.1f"  % zahl   # --> '1234567.9   '
  "%-012.1f" % zahl   # --> '1234567.9   '
  "%012.1f"  % zahl   # --> '0001234567.9'
  "%f"       % zahl   # --> '1234567.890000'   # Std: 6 Nachkommastellen
                      #
  text = "hallowelt"  #     |123456789012| (Ausgabespalten)
                      #
  "%s"       % text   # --> 'hallowelt'
  "%12s"     % text   # --> '   hallowelt'
  "%-12s"    % text   # --> 'hallowelt   '
  "%012s"    % text   # --> '   hallowelt'
  "%12.12s"  % text   # --> '   hallowelt'
  "%6.6s"    % text   # --> 'hallow'

HINWEIS: Die %(...)-Syntax erlaubt auch im C-Stil BENANNTE Parameter:

  alter = {                                   # Dictionary
     "tom"  : 18,                             #
     "hans" : 35,                             #
     "rick" : 92                              #
  }                                           #
                                              #
  "%(hans)4d, %(rick)03d %(tom)d, " % alter   # --> '  35, 092, 18'
  "%(hans)4d, %(rick)03d %(tom)d, " % {       # --> '  35, 092, 18'
     "thon" : 18, "hans" : 35, "rick" : 92 }  #