Link Search Menu Expand Document

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.

Algorithmus: Absolutbetrag von a
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, else
    • for
    • while

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
Syntax If-Statement
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')
Ausgabe
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
Syntax If-Else-Statement
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.

Syntax If-Else-Statement
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 if nur zwischen zwei Werten unterscheiden soll, kann man eine verkürzte Form nutzen: das ternäre If
Normales if
if a > b:
    max = a
else:
    max = b
Ternäres if
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
Syntax While-Schleife
while <BEDINGUNG>:
    <ANWEISUNGEN>
Beispiel: While-Schleife
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.

Fehler: Endlosschleife
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.

Fußgesteuerte Schleife in Python
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:

Fußgesteuerte Schleife in C
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:

Algorithmus: Durchschnittsnote
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.
Syntax For-Schleife
for <VARIABLE> in <LISTE>:
    <ANWEISUNGEN>
for i in [1, 2, 3]:
    print(i)
Ausgabe
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.

Mit range
# Laufe über die Elemente 1 bis 4
for i in range(1, 5):
    print(i)
Mit Liste
# 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.

  • break springt 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")
Ausgabe
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.

  • continue springt 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")
Ausgabe
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.

Wurzelberechnung ohne break
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
  • pass ist 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

Copyright © 2022 Thomas Smits