5.2 Schleifen
Eine Schleife ermöglicht es, einen Code-Block, den Schleifenkörper, mehrmals hintereinander auszuführen. Python unterscheidet zwei Typen von Schleifen: die while-Schleife als einfaches Schleifenkonstrukt und die for-Schleife zum Durchlaufen komplexerer Datentypen.
5.2.1 Die while-Schleife
Die while-Schleife haben wir bereits in dem Spiel »Zahlenraten« verwendet. Sie dient dazu, einen Code-Block so lange auszuführen, wie eine bestimmte Bedingung erfüllt ist. In unserem ersten Programm aus Abschnitt 4.3, »Das erste Programm«, wurde mithilfe einer while-Schleife so lange eine neue Zahl vom Spieler eingelesen, bis die eingegebene mit der gesuchten Zahl übereinstimmte.
Grundsätzlich besteht eine while-Schleife aus einem Schleifenkopf, in dem die Bedingung steht, sowie einem Schleifenkörper, der dem auszuführenden Code-Block entspricht. Beachten Sie, dass die Schleife läuft, solange die Bedingung erfüllt ist, und nicht, bis diese erfüllt ist.
Das folgende Beispiel ist eine etwas verknappte Variante des »Zahlenraten«-Spiels und soll die Verwendung der while-Schleife veranschaulichen:
geheimnis = 1337
versuch = -1
while versuch != geheimnis:
versuch = int(input("Raten Sie: "))
print("Sie haben es geschafft!")
Das Schlüsselwort while leitet den Schleifenkopf ein, dann folgen die gewünschte Bedingung und ein Doppelpunkt. In den nächsten Zeilen folgt, um eine Stufe weiter eingerückt, der Schleifenkörper. Dort wird eine Zahl vom Benutzer eingelesen und mit dem Namen versuch versehen. Dieser Prozess läuft so lange, bis die im Schleifenkopf genannte Bedingung erfüllt ist, bis also die Eingabe des Benutzers (versuch) mit der geheimen Zahl (geheimnis) übereinstimmt.
5.2.2 Abbruch einer Schleife
Da die im vorangegangenen Abschnitt eingeführte Variante des »Zahlenraten«-Spiels keine Hinweise darauf gibt, in welchen Bereichen die gesuchte Zahl liegt, kann ein Spiel recht lange dauern. Wir möchten dem Benutzer in diesem Abschnitt die Möglichkeit geben, das Spiel durch Eingabe einer 0 vorzeitig abzubrechen. Dies lässt sich durch eine Modifikation der Schleifenbedingung zu
versuch != geheimnis and versuch != 0
erreichen. Das ist in diesem Fall eine annehmbare Lösung, doch wenn die Schleifenbedingung an sich bereits komplex ist und zusätzlich noch mehrere Abbruchbedingungen hinzugefügt werden, leidet die Lesbarkeit des Quellcodes stark.
Eine alternative Lösung bietet das Schlüsselwort break, das an einer beliebigen Stelle im Schleifenkörper stehen kann und die Schleife abbricht.
geheimnis = 1337
versuch = -1
while versuch != geheimnis:
versuch = int(input("Raten Sie: "))
if versuch == 0:
print("Das Spiel wird beendet")
break
print("Sie haben es geschafft!")
Direkt nach der Benutzereingabe wird mit einer if-Anweisung geprüft, ob es sich bei der Eingabe um eine 0 handelt. Sollte dies der Fall sein, wird eine entsprechende Meldung ausgegeben und die while-Schleife mit break beendet.
5.2.3 Erkennen eines Schleifenabbruchs
Im vorangegangenen Abschnitt wurde dem Benutzer die Möglichkeit gegeben, das »Zahlenraten«-Spiel durch Eingabe einer 0 vorzeitig zu beenden. Leider wird die Erfolgsmeldung, die dem Spieler eigentlich signalisieren soll, dass er die gesuchte Zahl erraten hat, in jedem Fall nach Beendigung der Schleife angezeigt, also auch nachdem der Benutzer das Spiel abgebrochen hat:
Raten Sie: 10
Raten Sie: 20
Raten Sie: 30
Raten Sie: 0
Das Spiel wird beendet
Sie haben es geschafft!
An dieser Stelle suchen wir also nach einer Möglichkeit zu erkennen, ob die Schleife aufgrund der Schleifenbedingung oder aufgrund einer break-Anweisung beendet wurde. Dazu kann eine while-Schleife ähnlich wie eine if-Anweisung um einen else-Zweig erweitert werden. Der Code-Block, der zu diesem Zweig gehört, wird genau einmal ausgeführt, nämlich dann, wenn die Schleife vollständig abgearbeitet wurde, also die Bedingung zum ersten Mal False ergibt. Insbesondere wird der else-Zweig nicht ausgeführt, wenn die Schleife durch eine break-Anweisung vorzeitig abgebrochen wurde.
Betrachten wir dies an einem konkreten Beispiel:
geheimnis = 1337
versuch = -1
while versuch != geheimnis:
versuch = int(input("Raten Sie: "))
if versuch == 0:
print("Das Spiel wird beendet")
break
else:
print("Sie haben es geschafft!")
Aus Benutzersicht bedeutet dies, dass die Erfolgsmeldung ausgegeben wird, wenn die richtige Zahl geraten wurde:
Raten Sie: 10
Raten Sie: 1337
Sie haben es geschafft!
Wenn der Benutzer umgekehrt zum Spielabbruch die 0 eingibt, wird der else-Zweig nicht ausgeführt und damit auch keine Erfolgsmeldung ausgegeben:
Raten Sie: 10
Raten Sie: 0
Das Spiel wird beendet
5.2.4 Abbruch eines Schleifendurchlaufs
Wir haben mit break bereits eine Möglichkeit vorgestellt, den Ablauf einer Schleife zu beeinflussen. Eine zweite Möglichkeit bietet die continue-Anweisung, die im Gegensatz zu break nicht die gesamte Schleife, sondern nur den aktuellen Schleifendurchlauf abbricht. Um dies zu veranschaulichen, betrachten wir das folgende Beispiel, das bisher noch ohne continue-Anweisung auskommt:
while True:
zahl = int(input("Geben Sie eine Zahl ein: "))
ergebnis = 1
while zahl > 0:
ergebnis = ergebnis * zahl
zahl = zahl - 1
print("Ergebnis: ", ergebnis)
In einer Endlosschleife – also einer while-Schleife, deren Bedingung unter allen Umständen erfüllt ist – wird eine Zahl eingelesen und die Variable ergebnis mit 1 initialisiert. In einer darauffolgenden weiteren while-Schleife wird ergebnis so lange mit zahl multipliziert, wie die Bedingung zahl > 0 erfüllt ist. Zudem wird in jedem Durchlauf der inneren Schleife der Wert von zahl um 1 verringert.
Nachdem die innere Schleife durchlaufen ist, wird die Variable ergebnis ausgegeben. Wie Sie vermutlich bereits erkannt haben, berechnet das Beispielprogramm die Fakultät[ 13 ](Die Fakultät n! einer natürlichen Zahl n ist das Produkt aller natürlichen Zahlen, die kleiner oder gleich n sind: n! = 1 ⋅ 2 ⋅ … ⋅ (n – 1) ⋅ n. ) einer jeden eingegebenen Zahl:
Geben Sie eine Zahl ein: 4
Ergebnis: 24
Geben Sie eine Zahl ein: 5
Ergebnis: 120
Geben Sie eine Zahl ein: 6
Ergebnis: 720
Allerdings erlaubt der obige Code auch eine solche Eingabe:
Geben Sie eine Zahl ein: -10
Ergebnis: 1
Durch die Eingabe einer negativen Zahl ist die Bedingung der inneren Schleife von vornherein False, die Schleife wird also gar nicht erst ausgeführt. Aus diesem Grund wird sofort der Wert von ergebnis ausgegeben, der in diesem Fall 1 ist.
Das ist nicht das, was man in diesem Fall erwarten würde. Bei einer negativen Zahl handelt es sich um eine ungültige Eingabe. Idealerweise sollte das Programm also bei Eingabe einer ungültigen Zahl die Berechnung abbrechen und kein Ergebnis anzeigen. Dieses Verhalten kann über eine continue-Anweisung umgesetzt werden:
while True:
zahl = int(input("Geben Sie eine Zahl ein: "))
if zahl < 0:
print("Negative Zahlen sind nicht erlaubt")
continue
ergebnis = 1
while zahl > 0:
ergebnis = ergebnis * zahl
zahl = zahl - 1
print("Ergebnis: ", ergebnis)
Direkt nachdem die Eingabe des Benutzers eingelesen wurde, wird in einer if-Anweisung überprüft, ob es sich um eine negative Zahl handelt. Sollte das der Fall sein, wird eine entsprechende Fehlermeldung ausgegeben und der aktuelle Schleifendurchlauf abgebrochen. Das heißt, dass unmittelbar zum nächsten Schleifendurchlauf gesprungen wird, also die Schleifenbedingung geprüft und dann die nächste Zahl vom Benutzer eingelesen wird. Aus Benutzersicht bedeutet das, dass nach Eingabe einer negativen Zahl kein Ergebnis, sondern eine Fehlermeldung ausgegeben und zur Eingabe der nächsten Zahl aufgefordert wird.
Geben Sie eine Zahl ein: 4
Ergebnis: 24
Geben Sie eine Zahl ein: 5
Ergebnis: 120
Geben Sie eine Zahl ein: -10
Negative Zahlen sind nicht erlaubt
Geben Sie eine Zahl ein: -100
Negative Zahlen sind nicht erlaubt
Geben Sie eine Zahl ein: 6
Ergebnis: 720
Rückblickend möchten wir hier noch einmal den Unterschied zwischen break und continue herausarbeiten: Während break die Schleife vollständig abbricht, beendet continue nur den aktuellen Schleifendurchlauf, die Schleife an sich läuft weiter.
5.2.5 Die for-Schleife
Neben der bisher behandelten while-Schleife existiert in Python ein weiteres Schleifenkonstrukt, die sogenannte for-Schleife. Eine for-Schleife wird verwendet, um ein iterierbares Objekt[ 14 ](Ein iterierbares Objekt ist eine Instanz eines Datentyps, der das Iterator-Protokoll implementiert. Sie werden, abgesehen von den bereits bekannten iterierbaren Datentypen Listen und Strings, noch viele weitere kennenlernen, die sich mit einer for-Schleife durchlaufen lassen. Näheres zu iterierbaren Objekten erfahren Sie in Abschnitt 23.3, »Iteratoren«. ) zu durchlaufen. Dazu wird das Schlüsselwort for geschrieben, gefolgt von einem Bezeichner, dem Schlüsselwort in und dem iterierbaren Objekt. Darauf folgt, eine Ebene weiter eingerückt, der Schleifenkörper.
Über den gewählten Bezeichner kann im Schleifenkörper auf das jeweils aktuelle Element des iterierbaren Objekts zugegriffen werden. Konkret kann eine for-Schleife beispielsweise Listen oder Strings durchlaufen:
>>> for x in [1,2,3]:
... print(x)
...
1
2
3
>>> for c in "Python":
... print(c)
...
P
y
t
h
o
n
Sie werden im Laufe dieses Buchs noch einige Datentypen kennenlernen, die auf diese Weise mit einer for-Schleife durchlaufen werden können.
[»] Hinweis
Die for-Schleife, wie sie in Python existiert, ist kein Pendant des gleichnamigen Schleifenkonstrukts aus C oder Java. Sie ist mit der foreach-Schleife aus PHP oder Perl bzw. mit der range-based for-Schleife aus C++11 vergleichbar.
Die im Zusammenhang mit der while-Schleife besprochenen Schlüsselworte break und continue zum Abbrechen einer Schleife bzw. eines Schleifendurchlaufs (siehe Abschnitt 5.2.2 und Abschnitt 5.2.4) können auch mit der for-Schleife verwendet werden und haben dort dieselbe Bedeutung. Außerdem kann eine for-Schleife analog zur while-Schleife über einen else-Zweig verfügen, der genau dann ausgeführt wird, wenn die Schleife vollständig durchgelaufen ist und nicht mittels break vorzeitig abgebrochen wurde.
5.2.6 Die for-Schleife als Zählschleife
Im Zusammenhang mit der for-Schleife ist die eingebaute Funktion range besonders interessant. Sie erzeugt ein iterierbares Objekt, das alle ganzen Zahlen eines bestimmten Bereichs durchläuft:
range(stop)
range(start, stop)
range(start, stop, step)
Der Platzhalter start steht dabei für die Zahl, mit der begonnen wird. Die Schleife wird beendet, sobald stop erreicht wurde. Dabei sollten Sie wissen, dass der Schleifenzähler selbst niemals den Wert stop erreicht, er bleibt stets kleiner. In jedem Schleifendurchlauf wird der Schleifenzähler um step erhöht. Sowohl start als auch stop und step müssen ganze Zahlen sein. Wenn alle Werte angegeben sind, sieht die for-Schleife folgendermaßen aus:
for i in range(1, 10, 2):
print(i)
Die Zählvariable i beginnt jetzt mit dem Wert 1; die Schleife wird ausgeführt, solange i kleiner ist als 10, und in jedem Schleifendurchlauf wird i um 2 erhöht. Damit gibt die Schleife die Werte 1, 3, 5, 7 und 9 auf dem Bildschirm aus.
Eine for-Schleife kann nicht nur in positiver Richtung verwendet werden, es ist auch möglich, herunterzuzählen:
for i in range(10, 1, -2):
print(i)
In diesem Fall wird i zu Beginn der Schleife auf den Wert 10 gesetzt und in jedem Durchlauf um 2 verringert. Die Schleife läuft, solange i größer ist als 1, und gibt die Werte 10, 8, 6, 4 und 2 auf dem Bildschirm aus.
Damit bietet sich die for-Schleife geradezu an, um das Beispiel des letzten Abschnitts zur Berechnung der Fakultät einer Zahl zu überarbeiten. Es ist gleichzeitig ein Beispiel dafür, dass while- und for-Schleifen ineinander verschachtelt werden können:
while True:
zahl = int(input("Geben Sie eine Zahl ein: "))
if zahl < 0:
print("Negative Zahlen sind nicht erlaubt")
continue
ergebnis = 1
for i in range(2, zahl+1):
ergebnis = ergebnis * i
print("Ergebnis: ", ergebnis)
Nachdem eine Eingabe durch den Benutzer erfolgt ist und auf ihr Vorzeichen hin überprüft wurde, wird eine for-Schleife eingeleitet. Der Schleifenzähler i der Schleife beginnt mit dem Wert 2. Die Schleife läuft, solange i kleiner als zahl+1 ist: Der höchstmögliche Wert von i ist also zahl. In jedem Schleifendurchlauf wird dann die Variable ergebnis mit i multipliziert.