5 Kontrollstrukturen
Unter einer Kontrollstruktur versteht man ein Konstrukt zur Steuerung des Programmablaufs. Dabei unterscheidet man in Python zwei Arten von Kontrollstrukturen: Schleifen und Fallunterscheidungen. Schleifen dienen dazu, einen Code-Block mehrmals auszuführen. Fallunterscheidungen hingegen knüpfen einen Code-Block an eine Bedingung. Python kennt jeweils zwei Unterarten von Schleifen und Fallunterscheidungen, die wir im Folgenden behandeln werden.
Kontrollstrukturen können beliebig ineinander verschachtelt werden. Die Einrückungstiefe wächst dabei kontinuierlich.
5.1 Fallunterscheidungen
In Python gibt es zwei Arten von Fallunterscheidungen: die klassische if-Anweisung[ 10 ](Als Anweisung (engl. statement) wird eine einzelne Vorschrift im Quellcode bezeichnet. Es gibt einzeilige Anweisungen, beispielsweise Zuweisungen, aber auch mehrzeilige Anweisungen, die weitere Anweisungen enthalten können. Ein Beispiel für eine mehrzeilige Anweisung ist die angesprochene if-Anweisung.Beachten Sie, dass es einen Unterschied zwischen den Begriffen »Anweisung« und »Ausdruck« gibt. Im Gegensatz zu einer Anweisung hat ein Ausdruck immer einen Wert. ) und die bedingten Ausdrücke als erweiterte Möglichkeit der bedingten Ausführung von Code. Wir werden im Folgenden beide Arten der Fallunterscheidung detailliert besprechen und mit Beispielen erläutern. Dabei beginnen wir mit der if-Anweisung.
5.1.1 Die if-Anweisung
Die einfachste Möglichkeit der Fallunterscheidung ist die if-Anweisung. Eine if-Anweisung besteht aus einem Anweisungskopf, der eine Bedingung enthält, und aus einem Code-Block als Anweisungskörper (siehe Abbildung 5.1).
Der Code-Block wird nur ausgeführt, wenn sich die Bedingung als wahr herausstellt. Die Bedingung einer if-Anweisung muss dabei ein Ausdruck sein, der als Wahrheitswert (True oder False) interpretiert werden kann. Typischerweise werden hier die logischen Ausdrücke angewendet, die in Abschnitt 3.7 eingeführt wurden.
Als Beispiel betrachten wir eine if-Anweisung, die einen entsprechenden Text nur dann ausgibt, wenn die Variable x den Wert 1 hat:[ 11 ](Beachten Sie, dass für dieses und die folgenden Beispiele eine Variable x bereits existieren muss. Sollte dies nicht der Fall sein, bekommen Sie einen NameError. )
if x == 1:
print("x hat den Wert 1")
Selbstverständlich können Sie auch andere vergleichende Operatoren oder einen komplexeren logischen Ausdruck verwenden und mehr als eine Anweisung in den Körper schreiben:
if x < 1 or x > 5:
print("x ist kleiner als 1 ...")
print("... oder größer als 5")
In vielen Fällen ist es mit einer einzelnen if-Anweisung nicht getan, und man benötigt eine ganze Kette von Fallunterscheidungen. So möchten wir im nächsten Beispiel zwei unterschiedliche Strings ausgeben, je nachdem, ob x == 1 oder x == 2 gilt. Dazu können zwei aufeinanderfolgende if-Anweisungen verwendet werden:
if x == 1:
print("x hat den Wert 1")
if x == 2:
print("x hat den Wert 2")
Dies ist aus Sicht des Interpreters eine ineffiziente Art, das Ziel zu erreichen, denn beide Bedingungen werden in jedem Fall ausgewertet und überprüft. Die zweite Fallunterscheidung bräuchte jedoch nicht mehr in Betracht gezogen zu werden, wenn die Bedingung der ersten bereits True ergeben hat. Die Variable x kann unter keinen Umständen sowohl den Wert 1 als auch 2 haben. Um solche Fälle aus Sicht des Interpreters effizienter und aus Sicht des Programmierers übersichtlicher zu machen, kann eine if-Anweisung um einen oder mehrere sogenannte elif-Zweige[ 12 ](»elif« ist ein Kürzel für »else if«. ) erweitert werden. Die Bedingung eines solchen Zweiges wird nur evaluiert, wenn alle vorangegangenen if- bzw. elif-Bedingungen False ergeben haben.
Das oben genannte Beispiel können Sie mithilfe von elif folgendermaßen verfassen:
if x == 1:
print("x hat den Wert 1")
elif x == 2:
print("x hat den Wert 2")
Eine if-Anweisung kann um beliebig viele elif-Zweige erweitert werden (siehe Abbildung 5.2).
Im Quelltext könnte dies folgendermaßen aussehen:
if x == 1:
print("x hat den Wert 1")
elif x == 2:
print("x hat den Wert 2")
elif x == 3:
print("x hat den Wert 3")
Als letzte Erweiterung der if-Anweisung ist es möglich, alle bisher unbehandelten Fälle auf einmal abzufangen. So möchten wir beispielsweise nicht nur einen entsprechenden String ausgeben, wenn x == 1 bzw. x == 2 gilt, sondern zusätzlich in allen anderen Fällen eine Fehlermeldung, also zum Beispiel, wenn x == 35 gilt. Dazu kann eine if-Anweisung um einen else-Zweig erweitert werden. Ist dieser vorhanden, muss er an das Ende der if-Anweisung geschrieben werden (siehe Abbildung 5.3).
Konkret im Quelltext kann dies so aussehen:
if x == 1:
print("x hat den Wert 1")
elif x == 2:
print("x hat den Wert 2")
else:
print("Fehler: Der Wert von x ist weder 1 noch 2")
Der dem else-Zweig untergeordnete Code-Block wird nur dann ausgeführt, wenn alle vorangegangenen Bedingungen nicht erfüllt waren. Zu einer if-Anweisung darf maximal ein else-Zweig gehören. Im Beispiel wurde else in Kombination mit elif verwendet, was möglich, aber nicht zwingend ist. Abbildung 5.4 stellt den Aufbau einer if-Anweisung noch einmal übersichtlich dar.
[»] Hinweis
Sollten Sie bereits eine Programmiersprache wie C oder Java beherrschen, wird Sie interessieren, dass in Python kein Pendant zur switch/case-Kontrollstruktur dieser Sprachen existiert. Das Verhalten dieser Kontrollstruktur kann durch eine Kaskade von if/elif/else-Zweigen nachgebildet werden.
5.1.2 Bedingte Ausdrücke
Betrachten Sie in Anlehnung an den vorangegangenen Abschnitt einmal folgenden Code:
if x == 1:
var = 20
else:
var = 30
Wenn Sie bedenken, dass es sich lediglich um eine an eine Bedingung geknüpfte Zuweisung handelt, ist das Beispiel mit vier Zeilen bemerkenswert lang. Wir werden Ihnen jetzt zeigen, dass dieser Code mithilfe eines bedingten Ausdrucks (engl. »conditional expression«) in eine Zeile passt.
Ein solcher bedingter Ausdruck kann abhängig von einer Bedingung zwei verschiedene Werte annehmen. So ist es zum Beispiel möglich, var in derselben Zuweisung je nach Wert von x entweder auf 20 oder auf 30 zu setzen:
var = (20 if x == 1 else 30)
Die Klammern umschließen in diesem Fall den bedingten Ausdruck. Sie sind nicht notwendig, erhöhen aber die Übersicht. Der Aufbau einer Conditional Expression orientiert sich an der englischen Sprache und lautet folgendermaßen:
A if Bedingung else B
Sie nimmt dabei entweder den Wert A an, wenn die Bedingung erfüllt ist, oder andernfalls den Wert B. Sie könnten sich also vorstellen, dass die Conditional Expression nach dem Gleichheitszeichen entweder durch A oder B, also im obigen Beispiel durch 20 oder 30, ersetzt wird. Nach der Auswertung des bedingten Ausdrucks ergibt sich also wieder eine gültige Zuweisung.
Diese Form, eine Anweisung an eine Bedingung zu knüpfen, kann selbstverständlich nicht nur auf Zuweisungen angewandt werden. Im folgenden Beispiel wird mit derselben print-Anweisung je nach Wert von x ein anderer String ausgegeben:
print("x hat den Wert 1" if x == 1 else "x ist ungleich 1")
Beachten Sie, dass es sich bei Bedingung um einen logischen sowie bei A und B um zwei beliebige arithmetische Ausdrücke handeln kann. Eine komplexe Conditional Expression kann folglich auch so aussehen:
xyz = (a * 2 if (a > 10 and b < 5) else b * 2)
Dabei ist zu beachten, dass sich die Auswertungsreihenfolge der bedingten Ausdrücke von den normalen Auswertungsregeln von Python-Code unterscheidet. Es wird immer zunächst die Bedingung ausgewertet und erst dann, je nach Ergebnis, entweder der linke oder der rechte Teil des Ausdrucks. Ein solches Auswertungsvorgehen wird Lazy Evaluation genannt, da nicht alle Komponenten der Anweisung ausgewertet werden.
Die hier vorgestellten Conditional Expressions können in der Praxis dazu verwendet werden, umständlichen und langen Code elegant zu verkürzen. Allerdings geht das auf Kosten der Lesbarkeit und Übersichtlichkeit. Wir werden deshalb in diesem Buch nur in Ausnahmefällen davon Gebrauch machen. Es steht Ihnen allerdings frei, Conditional Expressions in Ihren eigenen Projekten nach Herzenslust zu verwenden.