Kontrollstrukturen
Überblick
Selbst die einfachsten Algorithmen brauchen die Möglichkeit, Fallunterscheidungen zu treffen. Beispielsweise muss man für die Berechnung des Absolutbetrages einer Zahl unterscheiden, ob die Zahl positiv oder negativ ist.
1. Wenn a >= 0: gib a zurück
2. Wenn a < 0: gib -a zurück
In der Programmierung werden solche Fallunterscheidungen durch Kontrollstrukturen realisiert. Sie erlauben es, Anweisungen abhängig von einer Bedingung auszuführen. Trifft die Bedingung zu, werden die Anweisungen ausgeführt, trifft sie nicht zu, dann werden sie übersprungen.
- Programme müssen Entscheidungen treffen oder Aufgaben wiederholen können
- Hierzu dienen Kontrollstrukturen (control structures)
if,elif,elseforwhile
Man unterscheidet bei den Kontrollstrukturen
- Bedingungen: Sie führen eine Gruppe von Anweisungen abhängig von einer Bedingung aus:
if,elif,else - Schleifen: Sie wiederholen eine Gruppe von Anweisungen abhängig von einer Bedingung:
for,while
Der Unterschied zwischen den Bedingungen und Schleifen liegt darin, was mit den Anweisungen passiert, die von der Kontrollstruktur kontrolliert werden. Die Bedingung entscheidet, ob sie ausgeführt werden, die Schleife, wie oft sie ausgeführt werden. Da bei der Schleife auch die Möglichkeit besteht, die Anweisungen kein Mal auszuführen, umfasst sie auch die Entscheidung über das ob.
If-Statement
Die einfachste Kontrollstruktur ist das if, das dazu dient eine Reihe von Anweisungen abhängig von einer Bedingung auszuführen. Die Bedingung wird nach dem Schlüsselwort if angegeben, die kontrollierten (bedingten) Anweisungen eingerückt in den folgenden Zeilen.
- Das If-Statement führt Anweisungen bedingt aus, d. h. nur wenn
<BEDINGUNG>wahr ist, wird<ANWEISUNGEN>ausgeführt
if <BEDINGUNG>:
<ANWEISUNGEN>
if ampel_farbe == 'grün':
fahr_weiter()
print("Wird immer ausgeführt")
Im Beispiel wird die Variable ampel_farbe darauf geprüft, ob sie den Wert 'grün' enthält. Wenn dem so ist, wird die Anweisung fahr_weiter() ausgeführt. Enthält ampel_farbe einen anderen Wert, werden die eingerückten Anweisungen übersprungen und das Programm danach fortgesetzt, hier also bei dem print.
- Welche Anweisungen zur Kontrollstruktur gehören wird über die Einrückung festgestellt
bedingung = True
if bedingung:
# Wenn bedingung wahr ist, wird dieser Code hier ausgeführt,
# andernfalls nicht
print('Bedingung ist wahr')
print('sonst würde das hier nicht ausgegeben')
# Nicht eingerückte Zeilen werden auf jeden Fall ausgeführt
print('Hallo, ich komme immer raus')
Damit hat Python eine absolute Besonderheit, die keine andere Programmiersprache hat. Die Formatierung des Quelltextes ist relevant für die Semantik des Programms. In anderen Sprachen kann man das Programm formatieren, wie man will, da die Zuordnung zu den Kontrollstrukturen über spezielle Zeichen ({ und } in Java, C, C++) oder Schlüsselworte (end in Ruby) erfolgt.
Damit man auch bei Komplexen Kontrollstrukturen den Überblick behält, muss man eine konsistente Einrückung verwenden. Am besten immer zwei der vier Leerzeichen. Tabs sollte man nicht verwenden, da sie, sobald sie mit Leerzeichen gemischt werden, sehr verwirrend sind.
Das folgende Beispiel zeigt dies für ein geschachteltes if.
a = True
b = False
if a:
print('a ist wahr')
if b:
print ('b ist wahr')
print('gehört zu a')
print('wird immer ausgegeben')
a ist wahr
gehört zu a
wird immer ausgegeben
If-Else-Statement
Es gibt viele Fälle, in denen man nicht nur dann etwas ausführen möchte, wenn eine Bedingung erfüllt ist, sondern auch etwas tun möchte, wenn sie nicht erfüllt ist.
Für diesen Zweck kann man das If-Else-Statement verwenden, bei dem zusätzliche Anweisungen unter dem else: angegeben werden können, die ausgeführt werden, wenn die Bedingung nicht zutrifft.
Das If-Else-Statement erlaubt, weitere Bedingungen zu prüfen
- Wenn
<BEDINGUNG>wahr ist, werden die<ANWEISUNGEN1>ausgeführt - Wenn
<BEDINGUNG>falsch ist, werden die<ANWEISUNGEN2>ausgeführt
if <BEDINGUNG>:
<ANWEISUNGEN1>
else:
<ANWEISUNGEN2>
if ampel_farbe == 'grün':
fahr_weiter()
else:
halt_an()
print("Fahr'n, fahr'n, fahr'n auf der Autobahn")
In diesem Beispiel wird die Farbe der Ampel geprüft. Ist sie 'grün', wird fahr_weiter() ausgeführt. Andernfalls wird halt_an() ausgeführt.
If-Elif-Else-Statement
Welche Lösung gibt es jetzt für Probleme, bei denen mehr als eine Möglichkeit bestehen? Z. B. kann eine Ampel grün, gelb oder rot sein.
Will man mehr als eine Bedingung prüfen, kommt das If-Elif-Else-Statement zum Einsatz. Es erlaubt, beliebig viele Bedingungen zu testen und abhängig davon Statements auszuführen. Trifft keine Bedingung zu, werden die Statements im else-Zweig ausgeführt. Der else-Zweig kann auch fehlen, d. h. er ist nicht zwingend notwendig.
if <BEDINGUNG1>:
<ANWEISUNGEN1>
elif <BEDINGUNG2>:
<ANWEISUNGEN2>
else:
<ANWEISUNGEN3>
Das If-Else-Statement erlaubt, weitere Bedingungen zu prüfen
- Wenn
<BEDINGUNG1>wahr ist, werden die<ANWEISUNGEN1>ausgeführt.<BEDINGUNG2>wird dann nicht mehr geprüft - Wenn
<BEDINGUNG1>falsch ist, wird<BEDINGUNG2>geprüft. Ist<BEDINGUNG2>wahr, werden die<ANWEISUNGEN2>ausgeführt. - Sind weder
<BEDINGUNG1>noch<BEDINGUNG2>wahr, werden die<ANWEISUNGEN3>ausgeführt
if ampel_farbe == 'grün':
fahr_weiter()
elif ampel_farbe == 'gelb':
gib_gas()
else:
halt_an()
print("Fahr'n, fahr'n, fahr'n auf der Autobahn")
Das Beispiel prüft die Variable ampel_farbe erst auf den Wert 'grün'. Ist dieser Test erfolgreich, wird fahr_weiter() ausgeführt und das Programm läuft bei dem print weiter.
Ist die ampel_farbe nicht 'grün', wird sie auf 'gelb' getestet. Wenn das Ergebnis True ist, wird gib_gas() ausgeführt und es geht beim print weiter. Ist das Ergebnis allerdings False, dann wird die Anweisung nach dem else ausgeführt, d. h. halt_an, bevor es beim print weiter geht.
Ternäres If
In der Programmierung kommt es häufig vor, dass man einen Wert abhängig von einer Bedingung setzen möchte. Deswegen gibt es für diesen Zweck eine spezielle, verkürzte Variante des if. Da es sich wie ein Operator mit drei Operanden verhält, wird es auch als ternäres If bezeichnet.
Die Syntax ist:
<WERT1> if <BEDINGUNG> else <WERT2>
Wenn die Bedingung <BEDINGUNG> wahr ist, wird <WERT1> zurück gegeben, wenn sie falsch ist <WERFT2>.
- Wenn
ifnur zwischen zwei Werten unterscheiden soll, kann man eine verkürzte Form nutzen: das ternäre If
if a > b:
max = a
else:
max = b
max = a if a > b else b
Beide Varianten sind vom Ergebnis her identisch. Der Unterschied besteht nur in der verkürzten Schreibweise und darin, dass bei der zweiten Variante sofort klar ist, dass die Variable max in Abhängigkeit von der Bedingung gesetzt werden soll. Bei der ersten Variante muss man etwas genauer hinschauen, damit das klar wird.
While-Schleife
Will man eine Anweisung mehrfach ausführen, verwendet man eine Schleife. Mit "mehrfach" kann
- kein Mal
- ein Mal
- n Mal
gemeint sein.
Die einfachste Schleife in Python ist die while-Schleife. Sie prüft eine Bedingung und wiederholt die zugeordneten Anweisungen (Schleifenrumpf genannt), solange diese Bedingung wahr ist.
Ist die Bedingung beim ersten Aufruf der Schleife nicht wahr, wird der Rumpf der Schleife überhaupt nicht ausgeführt. Deswegen spricht man von einer kopfgesteuerten Schleife.
- Die While-Schleife wiederholt
<ANWEISUNGEN>so lange, wie<BEDINGUNG>wahr ist
while <BEDINGUNG>:
<ANWEISUNGEN>
i = 1
while i < 5:
print(i**2) # -> 1,4,9,16
i = i + 1 # erhöht i um eins
Wenn man die Variablen, die in die Bedingung der Schleife verwendet wird, innerhalb der Schleife nicht verändert, dann liegt ein Programmierfehler vor: Die Schleife kann nicht enden, es liegt eine Endlosschleife vor.
i = 1
while i < 5:
print(i**2)
print("Diese Stelle wird nie erreicht")
Die While-Schleife prüft die Bedingung vor der ersten Ausführung, sodass diese am Anfang wahr sein muss, damit der Schleifenrumpf mindestens einmal ausgeführt werden soll. Will man, dass die Schleife mindestens einmal ausgeführt wird, also eine fußgesteuerte Schleife ist, dann muss man eine weitere Variable einführen, welche die Schleife kontrolliert.
weiter = True
i = 0
while weiter:
print(i**2)
i = i + 1
weiter = (i < 5)
Andere Programmiersprachen haben für diesen Zweck eine andere Form der Schleife (do-while-Schleife), Python verzichtet aber darauf und überlässt es der Programmiererin sich eine entsprechende Schleife selbst zu bauen. In C sähe das Beispiel mit einer do-while-Schleife wie folgt aus:
do {
printf("%d\n", i * i);
i = i + 1;
} while (i < 5);
For-Schleife
Einer der häufigsten Anwendungszwecke von Schleifen besteht darin, eine Operation auf die Elemente einer Liste anzuwenden, z. B. um die Durchschnittsnote aller Studierenden der Vorlesung zu bestimmen:
noten_summe = 0
anzahl = 0
Für jeden Studierenden s in der Liste ls
noten_summe = noten_summe + Note von S
anzahl = anzahl + 1
durchschnittsnote = noten_summe / anzahl
Listen werden in einem späteren Kapitel erläutert. An dieser Stelle muss als Einführung reichen, dass man Listen durch eckige Klammern symbolisiert und die einzelnen Elemente darin auflistet. Die Liste mit den Noten aus dem Algorithmus oben könnte man in Python schreiben als: [ 1.3, 2.3, 1.7, 2.7, 4.0, 1.3 ].
- Die For-Schleife erlaubt es Anweisungen eine definierte Anzahl von Malen zu wiederholen. Dabei nimmt die
<VARIABLE>nacheinander die Werte aus<LISTE>an.
for <VARIABLE> in <LISTE>:
<ANWEISUNGEN>
for i in [1, 2, 3]:
print(i)
1
2
3
Wer for-Schleifen aus anderen Programmiersprachen kennt, wird sich über die sehr beschränkten Möglichkeiten dieser Schleife in Python wundern. Dahinter steckt die Philosophie von Guido van Rossum, der die Sprache sehr schlank und einfach halten wollte.
Der Algorithmus zur Durchschnittsnote sieht in Python dann wie folgt aus:
noten_liste = [ 1.3, 2.3, 1.7, 2.7, 4.0, 1.3 ]
noten_summe = 0
anzahl = 0
for note in noten_liste:
noten_summe = noten_summe + note
anzahl = anzahl + 1
durchschnittsnote = noten_summe / anzahl
print(durchschnittsnote) # -> 2.216666666666667
Will man mit for über fortlaufende ganze Zahlen laufen, kann man anstatt einer Liste die range()-Funktion verwenden, die entsprechende Elemente liefert.
# Laufe über die Elemente 1 bis 4
for i in range(1, 5):
print(i)
# Laufe über die Elemente 1 bis 4
for i in [1, 2, 3, 4]:
print(i)
Bei range ist zu beachten, dass die obere Grenze exklusiv ist, d. h. range(a, b) liefert die Elemente von a bis b - 1.
continue und break
Es gibt in der Programmierung eine Reihe von Fällen, in denen man eine Schleife vorzeitig beenden möchte. Ein typisches Beispiel ist die Suche nach einem Wert (z. B. in einer Liste oder bei einer Berechnung): sobald der Wert gefunden ist, kann man die Schleife beenden und braucht nicht weiterzusuchen. Dies wird in Python mit dem Schlüsselwort break erreicht.
Ein anderer Fall liegt vor, wenn man die Schleife zwar weiterlaufen lassen möchte aber der aktuelle Schleifendurchlauf nicht mehr benötigt wird, z. B. weil man eine Element vor der Flinte hat, dass nicht bearbeitet werden muss. Hier kann man mit dem Schlüsselwort continue die Schleife dazu auffordern, sofort den nächsten Durchlauf zu starten.
breakspringt aus der umgebenden Schleife heraus
N = 64
for i in range(0, 10):
if i**2 == N:
print("Die Wurzel von", N, "ist", i)
break # Wurzel gefunden, springe aus Schleife
print("Nach der Schleife")
Die Wurzel von 64 ist 8
Nach der Schleife
Man kann sich break als einen Sprung zum ersten Statement nach der Schleife vorstellen, hier im Beispiel das print.
continuespringt zu nächsten Iteration der umgebenden Schleife
for num in range(2, 10):
if num % 2 == 0:
print(num, " ist gerade")
continue
print(num, " ist ungerade")
2 ist gerade
3 ist ungerade
4 ist gerade
5 ist ungerade
6 ist gerade
...
Das Beispiel ist etwas konstruiert, weil man normalerweise einfach ein if-else verwenden würde:
for num in range(2, 10):
if num % 2 == 0:
print(num, " ist gerade")
else:
print(num, " ist ungerade")
Trotzdem kann man die Funktionsweise von continue gut erkennen.
Generell ist die Verwendung von break und continue umstritten. Die einen sehen darin eine willkommene Möglichkeit, Schleifen effizient zu programmieren, die anderen eine versteckte Form des unbedingten Sprungs (goto), der seit 1968 verpönt ist (siehe Edgar Dijkstra: Go To Statement Considered Harmful).
Man kann jedes Problem auch ohne Verwendung von break oder continue lösen, indem man eine weitere Kontrollvariable einführt. Ob das immer elegant und sinnvoll ist, muss jede Entwicklerin selbst einscheiden.
N = 64
i = 2
cont = True
while i < 10 and cont:
if i**2 == N:
print("Die Wurzel von", N, "ist", i)
cont = False
i = i + 1
print("Nach der Schleife")
Zumindest bei der Wurzelberechnung scheint die Variante mit break die bessere zu sein.
Pass
Eine Besonderheit von Python, die man in anderen Programmiersprachen so nicht kennt, ist das pass-Statement. Es ist eine Anweisung, die nichts tut und nur dazu da ist, syntaktische Anforderungen der Sprache zu erfüllen.
- Python benötigt immer mindestens eine Anweisung in der Kontrollstruktur
passist eine Anweisung, die nichts tut
if ampel_farbe == 'grün':
pass # Kommt später, TODO
elif ampel_farbe == 'gelb':
gib_gas()
else:
halt_an()
Sie benutzen also pass immer dann, wenn die Syntax von Python eine Anweisung erfordert, Sie aber keine angeben wollen. Ein völlig korrektes, allerdings nutzloses, Python-Programm könnte so aussehen:
pass
pass
pass
pass