3.2. Kontrollstrukturen#

In unserem Kafka-Beispiel aus der zweiten Stunde haben wir bereits mit zwei Arten von Kontrollstrukturen zu tun gehabt: mit Fallunterscheidungen (Link öffnen, wenn das Publikationsjahr 1919 ist) und mit Schleifen (dasselbe mit jedem Eintrag in der Publikationsliste machen). Im Folgenden lernen wir die wichtigsten Kontrollstrukturen in Python kennen.

3.2.1. Fallunterscheidungen#

3.2.1.1. Bedingte Anweisung#

Bedingte Anweisungen, oder if-Anweisungen, haben die allgemeine Form:

Klasse str Klasse str

Beispiele:

# Nachricht wird ausgegeben, wenn die Liste autos ein Element mit dem Wert "Mercedes" enthält

autos = ["Mercedes", "Fiat", "Volvo", "BMW"]
if "Mercedes" in autos:
    print("Ein Mercedes steht in der Garage!")
Ein Mercedes steht in der Garage!
# Nachricht wird ausgegeben, wenn der Wert, der dem Schlüssel "Mercedes" im Dictionary autos zugeordnet ist, größer als 1 ist

autos = {"Mercedes": 2, "Fiat": 1, "Volvo": 1, "BMW": 3}
anzahl_mercedes = autos["Mercedes"]
if anzahl_mercedes > 1:
    print("Du hast " + str(anzahl_mercedes) + " Mercedes!")
Du hast 2 Mercedes!

Verständnisfrage

  • Was passiert, wenn autos den Schlüssel “Mercedes” nicht enthält?

# Wenn das Dictionary autos einen Schlüssel "Mercedes" enthält, wird überprüft, ob der Wert, der diesem Schlüssel zugeordnet ist, größer als 1 ist.
# Falls ja, wird eine Nachricht ausgegeben.

autos = {"Mercedes": 2, "Fiat": 1, "Volvo": 1, "BMW": 3}
if "Mercedes" in autos:
    anzahl_mercedes = autos["Mercedes"]
    if anzahl_mercedes > 1:
        print("Du hast " + str(anzahl_mercedes) + " Mercedes!")
Du hast 2 Mercedes!

Verständnisfrage

  • Wie könnte man diesen Code vereinfachen? Hinweis: Im Abschnitt “Zusammengesetzte Datentypen” habt ihr eine alternative Methode für den Zugriff auf Werte in einem Dictionary anstelle von dct["key"] kennengelernt.

anzahl_mercedes = autos.get("Mercedes", 0)
if anzahl_mercedes > 1:
    print("Du hast " + str(anzahl_mercedes) + " Mercedes!")
Du hast 2 Mercedes!

3.2.1.2. Verzweigung#

Verzweigungen, oder if-else-Anweisungen, haben die allgemeine Form:

Klasse str

Einfache Verzweigung

Beispiele:

# Wenn der Wert, der dem Schlüssel "Ibuprofen" zugeordnet ist, größer 0 ist, wird eine Nachricht ausgegeben.
# Wenn der Wert 0 (oder im theoretischen Fall kleiner 0) ist, wird eine Warnung ausgegeben.

medikamente = {"Ibuprofen": 30, "Paracetamol": 23, "Aspirin": 28}
anzahl_ibus = medikamente["Ibuprofen"]

if anzahl_ibus > 0:
    print("Du hast " + str(anzahl_ibus) + " Ibuprofen!")
else:
    print("Warnung: kein Ibuprofen mehr da!")
Du hast 30 Ibuprofen!

Eine spezielle Form von Verzweigung sind bedingte Ausdrücke. Diese werden verwendet, um einer Variable in Abhängigkeit von einer anderen Variable einen Wert zuzuweisen. Bedingte Ausdrücke stellen eine Kurzschreibweise für die folgende Verzweigung dar:

# Kompliziert
x = 1
if x == 2:
    var = 10
else:
    var = 20
# Einfach
var = (10 if x == 2 else 20)

3.2.1.3. Mehrfache Verzweigung#

Wenn mehr als zwei Fälle überprüft werden sollen, kann eine if-else-Anweisung mit beliebig vielen zusätzlichen bedingten Anweisungen kombiniert werden:

Klasse str

Mehrfache Verzweigung

Beispiele:

# Wenn der Wert, der dem Schlüssel "Ibuprofen" zugeordnet ist, größer als 5 ist, wird eine Nachricht mit dem Wert ausgegeben.
# Wenn der Wert genau dem Integer 5 entspricht, wird eine Warnung ausgegeben.
# In allen anderen Fällen wird die Nachricht "Achtung! Weniger als 5 Ibuprofen da!" ausgegeben.

medikamente = {"Ibuprofen": 30, "Paracetamol": 23, "Aspirin": 28}
anzahl_ibus = medikamente["Ibuprofen"]

if anzahl_ibus > 5:
    print("Du hast " + str(anzahl_ibus) + " Ibuprofen!")
elif anzahl_ibus == 5:
    print("Warnung: Nur noch 5 Ibuprofen da!")
else:
    print("Achtung! Weniger als 5 Ibuprofen da!")
Du hast 30 Ibuprofen!

Verständnisfrage

  • Welche/n Wert/e muss die Variable anzahl_ibus annehmen, damit die Nachricht “Achtung! Weniger als 5 Ibuprofen da!” ausgegeben wird?

3.2.2. Schleifen#

3.2.2.1. while-Schleife#

while-Schleifen werden verwendet, wenn ein Code-Block so lange ausgeführt werden soll, wie eine bestimmte Bedingung erfüllt ist. Die Bedingung steht im Schleifenkopf und wird überprüft, bevor der Code im Schleifenkörper ausgeführt wird. Wenn die Bedingung nicht (mehr) erfüllt ist, terminiert die Schleife. while-Schleifen haben die allgemeine Form:

Klasse str

while-Schleife

Beispiele:

# In jedem Schleifendurchlauf wird zunächst der Ausdruck anzahl_ibus > 0 ausgewertet.
# Wenn der Ausdruck zu True evaluiert wird, wird die Anweisung im Schleifenkörper ausgeführt, d.h. der Wert der Variable anzahl_ibus wird um 1 verringert.
# Wenn die Variable anzahl_ibus den Wert 0 annimmt, wird der Ausdruck im Schleifenkopf zu False evaluiert und die Schleife terminiert.
# Nach dem Terminieren der Schleife wird eine Warnung ausgegeben.

medikamente = {"Ibuprofen": 30, "Paracetamol": 23, "Aspirin": 28}

while medikamente["Ibuprofen"] > 0:
    medikamente["Ibuprofen"] -= 1

print("Achtung! Kein Ibuprofen mehr da!")
Achtung! Kein Ibuprofen mehr da!

Es ist auch möglich, while-Schleifen und bedingte Anweisungen zu kombinieren:

# In jedem Schleifendurchlauf wird zunächst der Ausdruck anzahl_ibus > 0 ausgewertet.
# Wenn der Ausdruck zu True evaluiert wird, wird überprüft, ob der Wert dem Integer 5 entspricht.
# Falls ja, wird eine Warnmeldung ausgegeben.
# Danach wird der Wert der Variable anzahl_ibus um 1 verringert.
# Wenn die Variable anzahl_ibus den Wert 0 annimmt, wird der Ausdruck im Schleifenkopf zu False evaluiert und die Schleife terminiert.
# Nach dem Terminieren der Schleife wird eine weitere Warnung ausgegeben.

medikamente = {"Ibuprofen": 30, "Paracetamol": 23, "Aspirin": 28}

while medikamente["Ibuprofen"] > 0:
    if medikamente["Ibuprofen"] == 5:
        print("Warnung: nur noch 5 Ibuprofen da!")
    medikamente["Ibuprofen"] -= 1

print("Achtung! Kein Ibuprofen mehr da!")
Warnung: nur noch 5 Ibuprofen da!
Achtung! Kein Ibuprofen mehr da!

Achtung: while-Schleifen laufen unendlich lange, wenn die Abbruchbedingung nie erfüllt ist:

# while True:
#     print("Dies ist eine unendliche Schleife")

Verständnisfrage

  • Im Abschnitt “Mehrfache Verzweigung” wurde zunächst der Wert des Schlüssels “Ibuprofen” einer Variable anzahl_ibus zugewiesen. In diesem Abschnitt entfällt dieser Schritt und es wird direkt medikamente["Ibuprofen"] verwendet. Was ist der Unterschied?

3.2.2.2. for-Schleife#

for-Schleifen werden verwendet, um iterierbare Objekte zu durchlaufen. Strings, Tupel, Listen, Dictionaries und Sets sind alle iterierbar. Im Kopf der for-Schleife steht anders als bei der while-Schleife keine Bedingung, sondern es wird eine Variable festgelegt, die als Platzhalter für den Wert der Elemente des Objekts dient. Diese Variable nennt man auch Laufvariable. Die for-Schleife “durchläuft” also im Grunde das Objekt, indem in jedem Schleifendurchlauf die Laufvariable den Wert des aktuellen Elements annimmt – und das so lange, bis es keine weiteren Elemente mehr gibt. Mithilfe des Variablennamens kann im Schleifenkörper auf den Wert des aktuellen Elements zugegriffen werden.

Klasse str

for-Schleife

Beispiele:

# In jedem Schleifendurchlauf nimmt die Laufvariable wort den Wert je eines Elements aus der Liste woerter nach der Reihenfolge der Indexpositionen an und es wird der aktuelle Wert der Laufvariable zusammen mit einem Integer, der die Zeichenanzahl des aktuellen Strings repräsentiert, ausgegeben

woerter = ["Netzwerkdurchsetzungsgesetz", "Abfallverzeichnisverordnung", "Haftpflichtversicherung", "Antivirenprogramm"]

for wort in woerter:
    print(wort, len(wort))
Netzwerkdurchsetzungsgesetz 27
Abfallverzeichnisverordnung 27
Haftpflichtversicherung 23
Antivirenprogramm 17

Wenn eine for-Schleife im Zusammenhang mit einem Set verwendet wird, ist die Reihenfolge, in der das Set durchlaufen wird, zufällig. Das hat den Grund, dass die Elemente eines Sets ungeordnet sind.

# In jedem Schleifendurchlauf nimmt die Laufvariable zahl den Wert eines Elements aus dem Set zahlen in einer zufälligen Reihenfolge an und es wird der aktuelle Wert der Variable zahl ausgegeben.

zahlen = {3, 5, 6, 1}

for zahl in zahlen:
    print(zahl)
1
3
5
6

Wie while-Schleifen können auch for-Schleifen mit bedingten Anweisungen kombiniert werden:

# In jedem Schleifendurchlauf nimmt die Laufvariable wort den Wert eines Elements aus der Liste woerter (s.o.) an.
# Zunächst wird die Zeichenanzahl des aktuellen Strings der Variable laenge als Wert zugewiesen.
# Dann wird geprüft, ob der Wert der Variable laenge größer als 20 ist.
# Falls ja, wird dem Dictionary lange_woerter ein Eintrag mit dem aktuellen Wert der Variable wort als Schlüssel und der Zeichenanzahl als Wert hinzugefügt.
# Wenn die Liste woerter keine weiteren Elemente mehr enthält, terminiert die Schleife.
# Danach wird das Dictionary lange_woerter ausgegeben.

lange_woerter = {}
for wort in woerter:
    laenge = len(wort)
    if laenge > 20:
        lange_woerter[wort] = laenge
print(lange_woerter)
{'Netzwerkdurchsetzungsgesetz': 27, 'Abfallverzeichnisverordnung': 27, 'Haftpflichtversicherung': 23}

Es muss jedoch beachtet werden, dass Elemente eines iterierbaren Objekts im Laufe einer Iteration nicht direkt verändert werden können:

tiere = ["Hund", "Elephant", "Igel", "Katze"]
for tier in tiere:
    tier = tier.lower()
# Änderungen wurden nicht übernommen
print(tiere)
['Hund', 'Elephant', 'Igel', 'Katze']

Das liegt daran, dass die Laufvariable nur für den Wert des aktuellen Elements steht, nicht für dieses Element selbst. Um Elemente im Schleifendurchlauf zu verändern, gibt es verschiedene Möglichkeiten:

1. Neues Objekt erstellen

tiere = ["Hund", "Elephant", "Igel", "Katze"]
tiere_klein = []
for tier in tiere:
    tiere_klein.append(tier.lower())
# Neues Objekt mit Änderungen wurde erstellt
print(tiere_klein)
['hund', 'elephant', 'igel', 'katze']

2. Funktion enumerate()

Klasse str

for-Schleife mit enumerate()

Mithilfe der Funktion enumerate() können zwei Laufvariablen parallel durch ein Objekt laufen. Das i steht im folgenden Beispiel für iterator und dient als Zählvariable: mit jedem Schleifendurchlauf (auch genannt Iteration) wird i um Eins erhöht; der Zählbeginn ist 0. Die Variable v steht für value, also für den Wert des jeweiligen Elements im durchlaufenen Objekt, also genau wie bei der bereits bekannten “einfachen” for-Schleife. In jedem Schleifendurchlauf nehmen beide Laufvariablen einen anderen Wert an. Der Unterschied zur bisher bekannten “einfachen” for-Schleife ist also, dass zusätzlich zur “Wertvariable” eine “Zählvariable” als zweite Laufvariable hinzugekommen ist. Mithilfe der Wertvariable kann wie zuvor im Schleifenkörper auf den Wert des aktuellen Elements im durchlaufenen Objekt zugegriffen werden. Mithilfe der Zählvariable kann nun zusätzlich direkt auf die Elemente des durchlaufene Objekts zugegriffen werden, und nicht nur auf den Wert der Elemente.

for i, v in enumerate(["Hund", "Elephant", "Igel", "Katze"]):
    print(i, v)
0 Hund
1 Elephant
2 Igel
3 Katze
tiere = ["Hund", "Elephant", "Igel", "Katze"]
for i, tier in enumerate(tiere):
    tiere[i] = tier.lower()
# Änderungen wurden übernommen
print(tiere)
['hund', 'elephant', 'igel', 'katze']

3. Funktion range()

for-Schleifen können auch als sogenannte Zählschleife verwendet werden. Das i steht im folgenden Beispiel wieder für iterator und dient wieder als Zählvariable; der Zählbeginn ist ebenfalls 0. In jedem Schleifendurchlauf kann damit auf das ì-te Element des durchlaufenen Objekts zugegriffen werden. Mithilfe des Iterators i wird also nacheinander in jeder Iteration auf ein Element aus dem Objekt zugegriffen. Der Unterschied zur “einfachen” for-Schleife und zur Variante mit enumerate() ist also, dass bei dieser Variante nur eine “Zählvariable” und keine “Wertvariable” verwendet wird.

Klasse str

for-Schleife als Zählschleife

for i in range(5):
    print(i)
0
1
2
3
4
tiere = ["Hund", "Elephant", "Igel", "Katze"]
for i in range(len(tiere)):
    tiere[i] = tiere[i].lower()
# Änderungen wurden übernommen
print(tiere)
['hund', 'elephant', 'igel', 'katze']

Zuletzt ist es auch möglich, mithilfe der Funktion zip() zwei Objekte gleichzeitig zu durchlaufen:

# Elemente aus zwei Listen kombinieren und ausgeben lassen mit zip()

artikel = ["der", "der", "das", "die"]
substantive = ["Baum", "Wald", "Meer", "Sonne"]
for a, w in zip(artikel, substantive):
    print(a + " " + w)
der Baum
der Wald
das Meer
die Sonne
# Elemente aus zwei Listen kombinieren mit zip() und eine neue Liste erstellen

artikel = ["der", "der", "das", "die"]
substantive = ["Baum", "Wald", "Meer", "Sonne"]
wortpaare = []
for a, s in zip(artikel, substantive):
    wortpaare.append(a + " " + s)
print(wortpaare)
['der Baum', 'der Wald', 'das Meer', 'die Sonne']
# Elemente aus zwei Listen kombinieren mit zip() und enumerate()

artikel = ["der", "der", "das", "die"]
substantive = ["Baum", "Wald", "Meer", "Sonne"]
for i, (a, s) in enumerate(zip(artikel, substantive)):
    substantive[i] = a + " " + s
substantive
['der Baum', 'der Wald', 'das Meer', 'die Sonne']

3.2.2.3. Schleifen abbrechen#

Es ist zudem möglich, einen Schleifendurchlauf (Iteration) oder die gesamte Schleife abhängig von einer Bedingung frühzeitig abzubrechen. Eine continue-Anweisung kann verwendet werden, um den aktuellen Schleifendurchlauf abzubrechen und direkt zum Schleifenkopf zu springen (= Iterationsabbruch). Eine break-Anweisung wird verwendet, um die Schleife komplett abzubrechen (= Schleifenabbruch). continue und break können sowohl mit while-Schleifen als auch mit for-Schleifen verwendet werden. Hier ein Beispiel mit einer for-Schleife:

# continue Anweisung

liste = ["Baum", "Wald", None, "Meer", None, "Sonne"]

for elem in liste:
    if elem is None:
        continue
    else:
        print(elem)
Baum
Wald
Meer
Sonne
# break Anweisung

liste = ["Baum", "Wald", None, "Meer", None, "Sonne"]

for elem in liste:
    if elem is None:
        break
    else:
        print(elem)
Baum
Wald

Der else-Zweig ist hier aber eigentlich nicht zwingend notwendig, sodass die Schleife vereinfacht werden kann zu:

for elem in liste:
    if elem is None:
        break
    print(elem)
Baum
Wald

Note

Das Objekt None repräsentiert in Python die Abwesenheit eines Werts. None hat den Datentyp NonType, und von diesem Datentyp gibt es nur ein einziges Objekt, nämlich eben None.

In ein paar Wochen lernt ihr ein Konstrukt kennen, das sich “List comprehension” nennt und das erlaubt, Schleifen, die zum Erstellen und Manipulieren von Listen verwendet werden, zu vereinfachen. Für den Anfang beschränken wir uns aber auf die hier vorgestellten Kontrollstrukturen.

3.2.3. Quellen#

  1. Ana Bell. Control Flow: Branching and Iteration. 2016. URL: https://ocw.mit.edu/courses/6-0001-introduction-to-computer-science-and-programming-in-python-fall-2016/resources/lecture-2-branching-and-iteration/.

  2. Peter Ernesti, Johannes und Kaiser. Python 3: Kontrollstrukturen. 2020. URL: https://openbook.rheinwerk-verlag.de/python/05_002.html.

  3. Python 3.11.3 Documentation. Built-in Constants: None. URL: https://docs.python.org/3/library/constants.html#None.

  4. Python 3.11.3 Documentation. Looping Techniques. URL: https://docs.python.org/3/tutorial/datastructures.html#looping-techniques.