33. String-Formatierung

Suchst du nach einer einfachen Möglichkeit, Variablen für die Anzeige zu formatieren und mit anderem Text zu mischen? Fügst du einer großen Zahl Tausender-Trennzeichen (Kommas in den USA) hinzu und formatierst Dezimalstellen nach deinen Wünschen? Du benötigst „String-Formatierung“.

Python bietet drei Möglichkeiten zum Formatieren von Zeichenfolgen. Die alte Methode (old string formatting), die ursprünglich aus der Formatierung älterer Sprachen wie C stammt. Der neuere Weg, der in Python 3 eingeführt wurde, sollte besser sein, war es aber wohl nicht. Und der neue Weg, der in Python 3.6 mit PEP-498 eingeführt wurde. Wir werden den neuesten Weg abdecken.

33.1. Kurzübersicht

Hier ist eine kurze Tabelle als Referenz für die Textformatierung. Lese weiter, um eine detaillierte Erläuterung der Funktionsweise der Textformatierung zu erhalten.

Beispiel für Formatierungsbefehle

Nummer

Format

Ausgabe

Beschreibung

x = 3.1415926

print(f"{x:.2f}")

3.14

2 Nachkommastellen

x = 3.1415926

print(f"{x:+.2f}")

+3.14

2 Nachkommastellen mit Vorzeichen

x = -1

print(f"{x:+.2f}")

-1.00

2 Nachkommastellen mit Vorzeichen

x = 3.1415926

print(f"{x:.0f}")

3

Keine Nachkommastellen (werden gerundet)

x = 5

print(f"{x:0>2d}")

05

mit Nullen auf der linken Seite auffüllen

x = 1000000

print(f"{x:,}")

1,000,000

Zahlenformat mit Komma als Trennzeichen

x = 0.25

print(f"{x:.2%}")

25.00%

Prozent

x = 1000000000

print(f"{x:.2e}")

1.00e+09

Exponenten-Notation

x = 11

print(f"{x:> 10d}")

........11

Rechtsbündig

x = 11

print(f"{x:<10d}")

11 ........

Linksbündig

x = 11

print(f"{x:^10d}")

....11....

Zentriert

33.2. Dezimalzahlen

Führe das folgende Programm aus, das mehrere Zufallszahlen ausgibt.

Eine unformatierte Liste mit Zahlen ausgeben
1
2
3
4
5
import random

for i in range(10):
    x = random.randrange(120)
    print("My number: ", x)

Die Ausgabe ist linksbündig und die Zahlen sehen schrecklich aus:

My number:  30
My number:  2
My number:  101
My number:  3
My number:  44
My number:  111
My number:  100
My number:  48
My number:  27
My number:  92

Wir können die String-Formatierung verwenden, um die Liste der Zahlen besser aussehen zu lassen, indem wir sie rechtsbündig ausrichten. Der erste Schritt besteht darin, die „Literal String Interpolation“ für die Zeichenfolge zu verwenden. Siehe unten:

import random

for i in range(10):
    x = random.randrange(120)
    print(f"My number: {x}")

Dies bringt unser Programm näher an die richtige Ausrichtung der Zahl, aber wir sind noch nicht ganz da. Siehst du, wie die Zeichenfolge mit f beginnt?

Die Zeichenfolge gibt die geschweiften Klammern {} nicht aus, sondern ersetzt sie durch den Wert in x. Die Ausgabe (unten) sieht genauso aus wie zuvor.

Die Ausgabe:
My number: 23
My number: 92
My number: 102
My number: 19
My number: 85
My number: 114
My number: 37
My number: 101
My number: 35
My number: 18

Zum rechtsbündigen Ausrichten fügen wir den geschweiften Klammern {} weitere Informationen zum Formatieren der Zahl hinzu:

Rechtsbündige Zahlenliste
1
2
3
4
5
import random

for i in range(10):
    x = random.randrange(120)
    print(f"My number: {x:3}")
Die Ausgabe:
My number:  37
My number: 108
My number: 117
My number:  55
My number:  19
My number:  97
My number:  78
My number:  12
My number:  29
My number:   0

Das ist besser. Wir haben die richtigen Zahlen! Aber wie funktioniert das? Das von uns hinzugefügte :3 ist nicht ganz intuitiv. Sieht so aus, als hätten wir gerade ein zufälliges Emoji hinzugefügt.

Hier ist die Aufteilung: Das { } teilt dem Computer mit, dass wir eine Zahl formatieren werden. Darin schreiben wir die Variable, die wir formatieren wollen, x in diesem Fall. Nach der Variablen setzen wir ein :, um dem Rechner mitzuteilen, dass wir ihm Formatierungsinformationen geben werden.

In diesem Fall geben wir eine 3 an, um eine Feldbreite von drei Zeichen anzugeben. Der Feldbreitenwert weist den Computer an, zu versuchen, die Nummer in ein drei Zeichen breites Feld einzugeben. Standardmäßig wird versucht, Zahlen rechtsbündig und Text linksbündig auszurichten.

Noch besser ist, dass das Programm nicht länger str() aufrufen muss, um die Zahl in einen String umzuwandeln! Lasse die String-Konvertierungen weg.

Was wäre, wenn wir große Zahlen hätten? Machen wir größere Zufallszahlen:

Größere Zahlen, die schwer zu lesen sind
1
2
3
4
5
import random

for i in range(10):
    x = random.randrange(100000)
    print(f"My number: {x:6}")

Dies ergibt eine Ausgabe, die richtig ausgerichtet ist, aber immer noch nicht gut aussieht.

Die Ausgabe:
My number:  89807
My number:   5177
My number:  24067
My number:  19887
My number:  54155
My number:  49288
My number:  31412
My number:  49633
My number:  43406
My number:  37398

Wo sind die Trennzeichen? Diese Liste würde mit Trennzeichen zwischen jeweils drei Ziffern besser aussehen. Schau dir das nächste Beispiel an, um zu sehen, wie sie hinzugefügt werden:

Hinzufügen eines Tausender-Trennzeichens
1
2
3
4
5
import random

for i in range(10):
    x = random.randrange(100000)
    print(f"My number: {x:6,}")

Die Ausgabe:

My number: 86,631
My number: 57,165
My number: 19,835
My number: 22,560
My number: 43,161
My number: 16,604
My number: 20,544
My number: 33,906
My number: 89,846
My number: 27,350

Wir haben nach dem Feldbreitenbezeichner ein Komma eingefügt, und jetzt haben unsere Zahlen Kommas. Das Komma muss nach dem Feldbreitenbezeichner stehen, nicht davor. Kommas werden bei der Berechnung der Feldbreite berücksichtigt. Beispielsweise hat 1,024 eine Feldbreite von 5 und nicht von 4.

Wir können mehrere Werte ausgeben und die Werte mit Text kombinieren. Führe den folgenden Code aus.

Mehrere Variablen gleichzeitig ausgeben
1
2
3
4
x = 5
y = 66
z = 777
print(f"A - '{x}' B - '{y}' C - '{z}'")

Das Programm ersetzt die geschweiften Klammern durch Zahlen und gibt den gesamten anderen Text in der Zeichenfolge aus:

A - '5' B - '66' C - '777'

33.3. Strings

Schauen wir uns an, wie Zeichenfolgen formatiert werden.

Die folgende Liste sieht schrecklich aus.

Schrecklich aussehende Liste
1
2
3
4
5
my_fruit = ["Apples","Oranges","Grapes","Pears"]
my_calories = [4, 300, 70, 30]

for i in range(4):
    print(my_fruit[i], "are", my_calories[i], "calories.")

Die Ausgabe:

Apples are 4 calories.
Oranges are 300 calories.
Grapes are 70 calories.
Pears are 30 calories.

Versuche es jetzt mit der format-Anweisung. Beachte, wie du zusätzlichen Text und mehr als einen Wert in dieselbe Zeile einfügen kannst.

Formatieren einer Obstliste
1
2
3
4
5
my_fruit = ["Apples", "Oranges", "Grapes", "Pears"]
my_calories = [4, 300, 70, 30]

for i in range(4):
    print(f"{my_fruit[i]:7} are {my_calories[i]:3} calories.")
Die Ausgabe:
Apples  are   4 calories.
Oranges are 300 calories.
Grapes  are  70 calories.
Pears   are  30 calories.

Das ist ziemlich cool und sieht so aus, wie wir es wollen. Was aber, wenn wir nicht wollten, dass die Zahlen rechts und der Text links ausgerichtet sind? Wir können die Zeichen < und > wie im folgenden Beispiel verwenden:

Festlegen der Rechts-/Linksausrichtung
1
2
3
4
5
my_fruit = ["Apples", "Oranges", "Grapes", "Pears"]
my_calories = [4, 300, 70, 30]

for i in range(4):
    print(f"{my_fruit[i]:>7} are {my_calories[i]:<3} calories.")
Die Ausgabe:
 Apples are 4   calories.
Oranges are 300 calories.
 Grapes are 70  calories.
  Pears are 30  calories.

33.4. Clock Example with Leading Zeros

Dies erzeugt eine Ausgabe, die nicht richtig ist:

Schrecklich aussehende Uhr
1
2
3
for hours in range(1,13):
    for minutes in range(0,60):
        print(f"Time {hours}:{minutes}")
Die nicht sehr gute Ausgabe:
Time 8:56
Time 8:57
Time 8:58
Time 8:59
Time 9:0
Time 9:1
Time 9:2

Wir müssen führende Nullen verwenden, um Zahlen in Uhren anzuzeigen. Anstatt eine 2 für die Feldbreite anzugeben, verwenden Sie stattdessen 02. Dadurch wird das Feld mit Nullen und nicht mit Leerzeichen aufgefüllt.

Formatierung der Zeitausgabe mit führenden Nullen
1
2
3
for hours in range(1, 13):
    for minutes in range(0, 60):
        print(f"Time {hours:02}:{minutes:02}")
Die Ausgabe:
Time 08:56
Time 08:57
Time 08:58
Time 08:59
Time 09:00
Time 09:01
Time 09:02

33.5. Gleitkommazahlen

Wir können auch die Ausgabe von Gleitkommazahlen steuern. Untersuche den folgenden Code und seine Ausgabe:

Formatieren von Gleitkommazahlen
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
x = 0.1
y = 123.456789

print(f"{x:.1}  {y:.1}")
print(f"{x:.2}  {y:.2}")
print(f"{x:.3}  {y:.3}")
print(f"{x:.4}  {y:.4}")
print(f"{x:.5}  {y:.5}")
print(f"{x:.6}  {y:.6}")

print()
print(f"{x:.1f}  {y:.1f}")
print(f"{x:.2f}  {y:.2f}")
print(f"{x:.3f}  {y:.3f}")
print(f"{x:.4f}  {y:.4f}")
print(f"{x:.5f}  {y:.5f}")
print(f"{x:.6f}  {y:.6f}")
Und hier ist die Ausgabe dieses Codes:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
0.1  1e+02
0.1  1.2e+02
0.1  1.23e+02
0.1  123.5
0.1  123.46
0.1  123.457

0.1  123.5
0.10  123.46
0.100  123.457
0.1000  123.4568
0.10000  123.45679
0.100000  123.456789

Ein Format von .2 bedeutet, dass die Zahl mit einer Genauigkeit von zwei Ziffern angezeigt wird. Leider bedeutet dies, wenn wir die Zahl 123 anzeigen, die drei signifikante Ziffern hat, erhalten wir die Zahl in wissenschaftlicher Notation 1.2e+02 anstatt gerundet.

Ein Format von .2f (beachte das f) bedeutet, dass die Zahl mit zwei Nachkommastellen angezeigt wird. Die Zahl 1 würde also als 1.00 und die Zahl 1.5555 als 1.56 angezeigt.

Ein Programm kann auch die Feldbreite angeben:

Angeben der Feldbreite
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
x = 0.1
y = 123.456789

print(f"My number: '{x:10.1}' and '{y:10.1}'")
print(f"My number: '{x:10.2}' and '{y:10.2}'")
print(f"My number: '{x:10.3}' and '{y:10.3}'")
print(f"My number: '{x:10.4}' and '{y:10.4}'")
print(f"My number: '{x:10.5}' and '{y:10.5}'")
print(f"My number: '{x:10.6}' and '{y:10.6}'")

print()
print(f"My number: '{x:10.1f}' and '{y:10.1f}'")
print(f"My number: '{x:10.2f}' and '{y:10.2f}'")
print(f"My number: '{x:10.3f}' and '{y:10.3f}'")
print(f"My number: '{x:10.4f}' and '{y:10.4f}'")
print(f"My number: '{x:10.5f}' and '{y:10.5f}'")
print(f"My number: '{x:10.6f}' and '{y:10.6f}'")

Das Format 10.2f bedeutet nicht 10 Stellen und zwei Stellen nach dem Komma. Es bedeutet eine Gesamtfeldbreite von 10. Es gibt also 7 Stellen vor der Dezimalstelle, die Dezimalstelle, die als eine weitere Stelle zählt, und 2 Stellen danach.

Die Ausgabe:
My number: '       0.1' and '     1e+02'
My number: '       0.1' and '   1.2e+02'
My number: '       0.1' and '  1.23e+02'
My number: '       0.1' and '     123.5'
My number: '       0.1' and '    123.46'
My number: '       0.1' and '   123.457'

My number: '       0.1' and '     123.5'
My number: '      0.10' and '    123.46'
My number: '     0.100' and '   123.457'
My number: '    0.1000' and '  123.4568'
My number: '   0.10000' and ' 123.45679'
My number: '  0.100000' and '123.456789'

33.6. Ausgabe von Dollar und Cent

Wenn du eine Gleitkommazahl für die Kosten ausgeben möchtest, verwende ein f. Siehe unten:

Angeben der Feldbreite
1
2
3
4
5
6
7
8
cost1 = 3.07
tax1 = cost1 * 0.06
total1 = cost1 + tax1

print(f"Cost:  ${cost1:5.2f}")
print(f"Tax:    {tax1:5.2f}")
print(f"-------------")
print(f"Total: ${total1:5.2f}")

Merke! Man könnte leicht vermuten, dass %5.2f fünf Ziffern vor dem Punkt, den Punkt, gefolgt von zwei Stellen bedeutet. Aber das tut es nicht. Dies bedeutet eine Gesamtfeldbreite von fünf, einschließlich des Punkts und der zwei Nachkommastellen. Hier ist die Ausgabe:

Die Ausgabe:
Cost:  $ 3.07
Tax:     0.18
-------------
Total: $ 3.25

Achtung! Der obige Code weist einen Fehler auf, der bei der Arbeit mit Finanztransaktionen häufig vorkommt. Findest du ihn? Versuche es mit dem folgenden erweiterten Codebeispiel:

Angeben der Feldbreite
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
cost1 = 3.07
tax1 = cost1 * 0.06
total1 = cost1 + tax1

print(f"Cost:  ${cost1:5.2f}")
print(f"Tax:    {tax1:5.2f}")
print(f"-------------")
print(f"Total: ${total1:5.2f}")

cost2 = 5.07
tax2 = cost2 * 0.06
total2 = cost2 + tax2

print()
print(f"Cost:  ${cost2:5.2f}")
print(f"Tax:    {tax2:5.2f}")
print(f"-------------")
print(f"Total: ${total2:5.2f}")

print()
grand_total = total1 + total2
print(f"Grand total: ${grand_total:5.2f}")
Die Ausgabe:
Cost:  $ 3.07
Tax:     0.18
------------
Total: $ 3.25

Cost:  $ 5.07
Tax:     0.30
-------------
Total: $ 5.37

Grand total: $ 8.63

Siehst du den Fehler? Wir müssen auf Rundungsfehler achten! Schaue dir dieses Beispiel an, es scheint, als sollte die Gesamtsumme $ 8.62 sein, aber das ist es nicht.

Die Ausgabeformatierung ändert nicht die Zahl, sondern nur die Ausgabe! Wenn wir die Ausgabeformatierung dahingehend geändert haben, dass sie drei Nachkommastellen enthält, wird der Grund für den Fehler offensichtlicher:

Die Ausgabe:
Cost:  $3.070
Tax:    0.184
-------------
Total: $3.254

Cost:  $5.070
Tax:    0.304
-------------
Total: $5.374

Grand total: $8.628

Auch hier ändert die Formatierung der Anzeige nichts an der Zahl. Verwende die Anweisung round, um den Wert zu ändern und wirklich zu runden. Siehe unten:

Angeben der Feldbreite
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
cost1 = 3.07
tax1 = round(cost1 * 0.06, 2)
total1 = cost1 + tax1

print(f"Cost:  ${cost1:5.2f}")
print(f"Tax:    {tax1:5.2f}")
print(f"-------------")
print(f"Total: ${total1:5.2f}")

cost2 = 5.07
tax2 = round(cost2 * 0.06, 2)
total2 = cost2 + tax2

print()
print(f"Cost:  ${cost2:5.2f}")
print(f"Tax:    {tax2:5.2f}")
print(f"-------------")
print(f"Total: ${total2:5.2f}")

print()
grand_total = total1 + total2
print(f"Grand total: ${grand_total:5.2f}")
Die Ausgabe:
Cost:  $ 3.07
Tax:     0.18
-------------
Total: $ 3.25

Cost:  $ 5.07
Tax:     0.30
-------------
Total: $ 5.37

Grand total: $ 8.62

Die Rundungsanweisung steuert, auf wie viele Stellen nach der Dezimalstelle gerundet wird. Der gerundete Wert wird zurückgegeben, der ursprüngliche Wert wird jedoch nicht geändert. Siehe unten:

Angeben der Feldbreite
1
2
3
4
5
6
x = 1234.5678
print(round(x, 2))
print(round(x, 1))
print(round(x, 0))
print(round(x, -1))
print(round(x, -2))

Siehe unten, wie sich die Eingabe der round()-Funktionswerte wie -2 auf die Nachkommastellen auf die Ausgabe auswirkt:

Die Ausgabe:
1234.57
1234.6
1235.0
1230.0
1200.0

33.7. Verwendung in Arcade-Programmen

Wir müssen nicht nur Zeichenfolgen für Ausgabeanweisungen formatieren. Das Beispiel timer.py verwendet die Formatierung von Zeichenfolgen, um einen On-Screen-Timer zu erstellen:

Code von timer.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def on_draw(self):
    """ Use this function to draw everything to the screen. """

    # Start the render. This must happen before any drawing
    # commands. We do NOT need an stop render command.
    arcade.start_render()

    # Calculate minutes
    minutes = int(self.total_time) // 60

    # Calculate seconds by using a modulus (remainder)
    seconds = int(self.total_time) % 60

    # Figure out our output
    output = f"Time: {minutes:02d}:{seconds:02d}"

    # Output the timer text.
    arcade.draw_text(output, 300, 300, arcade.color.BLACK, 30)

def update(self, delta_time):
    """
    All the logic to move, and the game logic goes here.
    """
    self.total_time += delta_time

Du kannst den Programmcode auch verwenden, um die Punktzahl oder andere Statistiken anzuzeigen, die du dem Spieler anzeigen möchten.