Verzweigungen#

When you come to a fork in the road, take it.
— Yogi Berra
Folien/PDF#
Bedingtes Verzweigen#
Ein Computer muss oft entscheiden wie Informationen verarbeitet werden sollen. Dafür muss er im Programm die Möglichkeit haben, bestimmte Statements oder Programmteile nur in bestimmten Fällen auszuführen. Hierfür bieten alle Programmiersprachen das Konzept der Verzweigung an.
Die Einfachste Form der Verzweigung sind bedingte Verzweigungen, welche einen Code-Block nur bei Zutreffen einer logischen Bedingung ausführen. In Python ist dafür die if
-Anweisung (Wenn-Dann) vorgesehen, welche einem Statement vorsteht, welches nur bei Zutreffen einer Bedingung ausgeführt wird. Es ist üblich die Statements auf eine neue Zeile zu schreiben. Dann müssen sie eingerückt werden.
bedingung=True
if bedingung:
# wird nur ausgeführt wenn Bedingung True ist
print(f"Der Block mit 'bedingung={bedingung}' wurde ausgeführt. 1")
bedingung=False
if bedingung:
# wird nur ausgeführt wenn Bedingung True ist
print(f"Der Block mit 'bedingung={bedingung}' wurde ausgeführt. 2")
Der Block mit 'bedingung=True' wurde ausgeführt. 1
Mit dem logischen Operator not
kann man die Bedingungen negieren und mit and
, or
und Klammern kombinieren.
bedingung=True
if not bedingung:
# wird nur ausgeführt wenn Bedingung True ist
print(f"Der Block mit 'bedingung={bedingung}' wurde ausgeführt.")
bedingung=0
if bedingung:
# wird nur ausgeführt wenn Bedingung equivalent mit True ist
print(f"Der Block mit 'bedingung'={bedingung} wurde ausgeführt.")
bedingung=2
if bedingung:
# wird nur ausgeführt wenn Bedingung equivalent mit True ist
print(f"Der Block mit 'bedingung'={bedingung} wurde ausgeführt.")
if not bedingung:
# wird nur ausgeführt wenn Bedingung True ist
print(f"Der Block mit 'bedingung={bedingung}' wurde ausgeführt.")
Der Block mit 'bedingung'=2 wurde ausgeführt.
Strings die leer und die Länge 0 haben entsprechen dem logischen Wert False
und nicht leere dem logischen Wert True
.
bedingung='' # leerer String
if bedingung:
# wird nur ausgeführt wenn Bedingung equivalent mit True ist
print(f"Der Block mit 'bedingung'={bedingung} wurde ausgeführt.")
bedingung=' '
if bedingung:
# wird nur ausgeführt wenn Bedingung equivalent mit True ist
print(f"Der Block mit 'bedingung'={bedingung} wurde ausgeführt.")
Der Block mit 'bedingung'= wurde ausgeführt.
Das gleiche gilt für Listen und Dictionaries, wenn diese leer sind (False
) oder befüllt (True
).
bedingung=[] # leerer Liste
if bedingung:
# wird nur ausgeführt wenn Bedingung equivalent mit True ist
print(f"Der Block mit 'bedingung'={bedingung} wurde ausgeführt.")
bedingung=['nicht_leer'] # nicht leere Liste
if bedingung:
# wird nur ausgeführt wenn Bedingung equivalent mit True ist
print(f"Der Block mit 'bedingung'={bedingung} wurde ausgeführt.")
Der Block mit 'bedingung'=['nicht_leer'] wurde ausgeführt.
Damit lässt sich im Code schnell prüfen ob z.B. bereits Elemente in einer Liste enthalten sind und diese z.B. weiterverarbeitet werden sollen.
Bei komplexeren Datentypen, wie Objekten, die den Wert None
annehmen können, wird dieser auch als False
interpretiert und alles andere als True
, womit man wiederum prüfen kann, ob die Variable schon belegt worden ist.
bedingung=None # nicht belegt
if bedingung:
# wird nur ausgeführt wenn Bedingung equivalent mit True ist
print(f"Der Block mit 'bedingung'={bedingung} wurde ausgeführt.")
bedingung="nicht_None" # belegt
if bedingung:
# wird nur ausgeführt wenn Bedingung equivalent mit True ist
print(f"Der Block mit 'bedingung'={bedingung} wurde ausgeführt.")
bedingung=None # nicht belegt
if bedingung is not None:
# wird nur ausgeführt wenn Bedingung equivalent mit True ist
print(f"Der Block mit 'bedingung'={bedingung} wurde ausgeführt.")
bedingung="nicht_None" # belegt
if bedingung is not None:
# wird nur ausgeführt wenn Bedingung equivalent mit True ist
print(f"Der Block mit 'bedingung'={bedingung} wurde ausgeführt.")
Der Block mit 'bedingung'=nicht_None wurde ausgeführt.
Der Block mit 'bedingung'=nicht_None wurde ausgeführt.
Die Alternative#
Oft kommt es vor, dass nicht nur etwas ausgeführt werden soll, wenn die Bedingung wahr ist, sondern im anderen Fall auch etwas ausgeführt werden soll. Dafür gibt es die else
-Anweisung, welche ausschließlich nach einem if
folgen darf und bei mehreren Zeilen auf gleicher Höhe eingerückt werden muss, wie das if
welches es beschließt.
bedingung=True
if bedingung:
# wird nur ausgeführt wenn Bedingung True ist
print(f"Der Block mit 'bedingung={bedingung}' wurde ausgeführt.")
else:
# wird nur ausgeführt wenn Bedingung False ist
print(f"Der alternative Block mit 'bedingung={bedingung}' wurde ausgeführt.")
Der Block mit 'bedingung=True' wurde ausgeführt.
bedingung=False
if bedingung:
# wird nur ausgeführt wenn Bedingung True ist
print(f"Der Block mit 'bedingung={bedingung}' wurde ausgeführt.")
else:
# wird nur ausgeführt wenn Bedingung False ist
print(f"Der alternative Block mit 'bedingung={bedingung}' wurde ausgeführt.")
Der alternative Block mit 'bedingung=False' wurde ausgeführt.
Ein typisches Beispiel ist das Abfangen von Divisionen durch 0. Da man bei Berechnungen nicht immer garantieren kann, dass der Nenner 0 sein kann. Da diese nicht definiert ist, führt sie zu einem Programmfehler und ggf. zu einem Programmabsturz.
zaehler = 5
nenner = 0
ergebnis = zaehler / nenner
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
Cell In[8], line 3
1 zaehler = 5
2 nenner = 0
----> 3 ergebnis = zaehler / nenner
ZeroDivisionError: division by zero
Um dies abzufangen können wir eine if-else
-Verzweigung nutzen und dem Ergebnis den Wert None
(im Sinne von ‘nicht definiert’) zuweisen.
nenner = 0
if nenner: # der Wahrheitswert eines int-Wertes ist False bei 0 und Wahr für != 0
ergebnis = zaehler / nenner
else:
print("Teilung durch 0")
ergebnis = None
print(f"Das Ergebnis von {zaehler}/{nenner} = {ergebnis}")
Teilung durch 0
Das Ergebnis von 5/0 = None
Da man ferner bei Python durch die dynamische Typisierung gar nicht garantieren kann, dass zaehler
und nenner
vom richtigen Datentyp int
sind, ist es sinnvoll eine Typprüfung hinzuzufügen. Hierfür prüfen wir zuerst den Datentyp mit der bekannten Funktion type()
bevor wir die Prüfung auf 0-Teilung machen. Dafür verschachteln wir die if-else
Bedingungen.
zaehler = 'keine_zahl'
nenner = 0
if type(zaehler) == int:
if type(nenner) == int:
if nenner: # der Wahrheitswert eines int-Wertes ist False bei 0 und Wahr für != 0
ergebnis = zaehler / nenner
else:
print("Teilung durch 0")
ergebnis = None
else:
print(f"Nenner nicht vom Datentyp `int`, sondern vom Typ {type(nenner)}")
ergebnis = None
else:
print(f"Zaehler nicht vom Datentyp `int`, sondern vom Typ {type(zaehler)}")
ergebnis = None
print(f"Das Ergebnis von {zaehler}/{nenner} = {ergebnis}")
Zaehler nicht vom Datentyp `int`, sondern vom Typ <class 'str'>
Das Ergebnis von keine_zahl/0 = None
Alternatives Verzweigen#
Gibt es wie im letzten Beispiel mehrere verschachtelte Alternativen, so wird der Code sehr schnell unübersichtlich und man braucht eine kompaktere Schreibweise. Hierfür gibt es in Python die elif
-Anweisung, welche einfach nur eine Kurzform von else if
ist und keines weiteren Einrückens bedarf. So, kann man den vorherigen Code leserlicher schreiben als:
zaehler = 'keine_zahl'
nenner = 0
ergebnis = None
if not isinstance(nenner, int):
print(f"Nenner nicht vom Datentyp `int`, sondern vom Typ {type(nenner)}")
elif not isinstance(zaehler, int):
print(f"Zaehler nicht vom Datentyp `int`, sondern vom Typ {type(zaehler)}")
elif not nenner:
print("Teilung durch 0")
else:
ergebnis = zaehler / nenner
print(f"Das Ergebnis von {zaehler}/{nenner} = {ergebnis}")
Zaehler nicht vom Datentyp `int`, sondern vom Typ <class 'str'>
Das Ergebnis von keine_zahl/0 = None
Hierbei haben wir:
als erstes die Bedingung
type(zaehler) == int
ersetzt durch die Standardfunktionisinstance(zaehler, int)
welche identisch ist und einfacher zu lesen.wir haben alle Fehlerfälle zuerst bearbeitet, um sicher zu stellen, dass sie vor Ausführung der Berechnung abgefragt werden
so prüfen wir erst ob der
zaehler
nicht vom Datentypint
ist und geben in diesem Fall eine Fehlermeldung ausIst das nicht der Fall, so könnte
nenner
nicht vom Datentypint
sein und würden in diesem Fall eine andere Fehlermeldung ausgebendann muss muss der
nenner
vom Datentypint
sein und wir prüfen ob er 0 ist mit einer entsprechenden Fehlermeldungda in allen drei Fällen das
ergebnis
den WertNone
hat, haben wir diese Zuweisung vor denif
-Block gesetztder letzte
else
Block wird nur erreicht, wenn all dies nicht zutrifft, alsozaehler
undnenner
vom Datentypenint
undnenner
nicht 0 ist. Nur in diesem Fall wirdergebnis
mit dem Wert der Teilung belegt
zaehler = 10
nenner = []
ergebnis = None
if not nenner:
print("Teilung durch 0")
elif not isinstance(nenner, int):
print(f"Nenner nicht vom Datentyp `int`, sondern vom Typ {type(nenner)}")
elif not isinstance(zaehler, int):
print(f"Zaehler nicht vom Datentyp `int`, sondern vom Typ {type(zaehler)}")
else:
ergebnis = zaehler / nenner
print(f"Das Ergebnis von {zaehler}/{nenner} = {ergebnis}")
Teilung durch 0
Das Ergebnis von 10/[] = None
Viele Alternativen#
In Python 3.10 wurde das Match-Statement eingeführt, was es in vielen anderen Sprachen bereits gibt. Es erlaub eine Variable mit mehren möglichen Werten zu vergleichen.
Traditionell (viele elif):
if Variable == ValueA:
StatementA
elif Variable == ValueB:
StatementB
else:
StatementC
Neu (match-case):
match Variable:
case ValueA:
StatementA
case ValueB:
StatementB
case _:
StatementC