Additum: Mehrfache Verzweigungen und Verknüpfung von Bedingungen
Im Rahmen des aktuellen Kapitels haben wir Verzweigungen näher betrachtet. Dabei wurden zwei Einschränkungen vorgenommen:
Wir haben maximal zwei unterschiedliche Anweisungsblöcke hinterlegt.
Besteht die Möglichkeit, weitere Fallunterscheidungen vorzunehmen und auf diese Weise mehr mögliche Anweisungsblöcke zu hinterlegen?
Unsere bisherigen Bedingungen waren recht einfach gestrickt.
Kann man nun weitere Bedingungen aus einzelnen Teilbedingungen "verknüpfen" und damit "mächtigere" Bedingungen realisieren?
Mit der Aufhebung dieser Einschränkung wollen wir uns jetzt beschäftigen.
Mehrfache Verzweigungen
# Autor: Christian Graf# Datum: 22.03.2011# Beschreibung: Ausgabe aller maximal zweistelligen Zahlen mit# # Zusatzinformation über den Rest der Division durch 3for zahl in range(100): if (zahl % 3 == 0): print(zahl,"- ist durch drei teilbar") else: if (zahl % 3 == 1): print(zahl,"- ist nicht durch drei teilbar (Rest 1)") else: print(zahl,"- ist nicht durch drei teilbar (Rest 2)")
Für die mehrfachen Verzweigungen betrachten wir das vorliegende Programm. Aus der Beschreibung entnehmen wir, dass hier die Divisionsreste aller maximal zweistelligen Zahlen durch 3 betrachtet werden.
Innerhalb des Alternativblockes der ersten Verzweigung findet man eine weitere Verzweigung. Die erste Verzweigung (Zeile 06) unterscheidet zwischen einer aufgehenden Division und einer nichtaufgehenden Division. Geht die Division durch 3 auf, es bleibt also Rest 0, so erfolgt eine direkte Ausgabe der Information.
Geht die Division nicht auf, es bleibt also ein Rest, so findet eine weitere Unterscheidung (Zeile 09) statt. Diesmal wird geprüft, ob bei der Division der Rest 1 übrig bleibt. Entsprechend der erfüllten oder nicht erfüllten Bedingung wird der zugehörige Text ausgegeben.
Aufgabe 1
Betrachte die beiden Zeichenketten, die im Alternativteil ausgegeben werden. Siehst du eine Möglichkeit, die gleiche Ausgabe ohne eine weitere Verzweigung zu erhalten?
Wenn ja, programmiere diese!
Lösung:
# Autor: Christian Graf# Datum: 22.03.2011# Beschreibung: Ausgabe aller maximal zweistelligen Zahlen mit# # Zusatzinformation ueber den Rest der Division durch 3for zahl in range(100): if (zahl % 3 == 0): print(zahl,"- ist durch drei teilbar") else: print(zahl,"- ist nicht durch drei teilbar (Rest",zahl % 3,")")
Die beiden Zeichenketten unterscheiden sich nur um die entsprechenden Werte des Restes. Da dieser in engem Zusammenhang zu der angebenen Bedingung steht, können wir die Bedingung bzw. die Verzweigung auch streichen und das Ergebnis der Restberechnung direkt in die auszugebende Zeichenkette integrieren.
Die im Rahmen der letzten Aufgabe betrachtete Vereinfachung ist sehr geschickt und erspart uns eine weitere Verzweigung. Was ist aber, wenn wir statt dem numerischen Wert des Restes den entsprechenden Wert als Text, also "zwei" oder "eins", ausgeben lassen wollen? Das Vorgehen aus der letzten Aufgabe funktioniert nun leider nicht mehr und wir müssen die ineinander verschachtelte Verzweigung, die anfangs vorgestellt wurde, nutzen.
Doch auch diese lässt sich noch vereinfachen bzw. so umgestalten, dass sie für uns Menschen einfacher zu lesen ist. Doch nicht nur dies ist ein Vorteil, es gibt noch weitere. Und genau dafür kommen die sogenannten mehrfachen Verzweigungen ins Spiel.
Bei der mehrfachen Verzweigung gibt es mehrere Bedingungen, die der Reihe nach ausgewertet und damit geprüft werden. In dem vorliegenden Fall wären das die beiden bereits bekannten Bedingungen (zahl % 3 == 0) bzw. (zahl % 3 == 1). Sobald der Interpreter die erste Bedingung findet, die bei der Auswertung True ergibt, wird der zugehörige Anweisungsblock ausgeführt. Wichtig ist, dass dann keine weitere Bedingung mehr geprüft bzw. ausgewertet wird. Die gesamte Mehrfachverzweigung ist damit beendet. Sollte auch die letzte angegebene Bedingung bei der Auswertung False ergeben, so wird der Anweisungsblock, der zum else-Teil gehört ausgeführt. Diesen muss es aber nicht geben. In solchen Fällen endet die mehrfache Verzweigung ohne Ausführung auch nur eines einzigen Anweisungsblockes.
Muster:
if (Bedingung1): # Anweisungen, die ausgeführt # werden, wenn die Bedingung1 wahr istelif (Bedingung2): # Anweisungen, die ausgeführt # werden, wenn die Bedingung2 wahr istelse: # Anweisungen, die ausgeführt # werden, wenn die bisherigen Bedingungen alle falsch waren# Ende der mehrfachen Verzweigung
Im obigen Muster ist dir sicherlich bereits das reservierte Wort elif aufgefallen. Dies stellt eine Kombination aus den bekannten reservierten Wörtern else und if dar. Übersetzen kann man es am besten mit "andernfalls, falls (Bedingung2) wahr ist ..."
Auf das reservierte Wort elif folgt wie gehabt eine Bedingung und der übliche Doppelpunkt. Dieser leitet den zugehörigen Anweisungsblock ein. Die entsprechenden Anweisungen des zugehörigen Körpers bzw. Blockes müssen eingerückt werden. Dabei ist zu beachten, dass das reservierte Wort elif auf der Höhe des reservierten Wortes if steht. Ansonsten würden die Anweisungen noch zum Block gehören und in vielen Fällen einen Syntaxfehler ergeben.
Das obige Muster zeigt nur einen weiteren Block bzw. eine weitere Bedingung, die in die Verzweigung integriert wurde. Es können - entsprechend dem obigen Muster - aber noch weitere Bedingungen und zugehörige Anweisungsblöcke integriert werden.
Aufgabe 2
Integriere die vorgestellte Möglichkeit der mehrfachen Verzweigung in das Programm vom Anfang. Kannst du eine zweite Realisierung der mehrfachen Verzweigung angeben, die die gleiche Ausgabe erzeugt?
Lösung:
# Autor: Christian Graf# Datum: 22.03.2011# Beschreibung: Ausgabe aller maximal zweistelligen Zahlen mit# # Zusatzinformation ueber den Rest der Division durch 3for zahl in range(100): if (zahl % 3 == 0): print(zahl,"- ist durch drei teilbar") elif (zahl % 3 == 1): print(zahl,"- ist nicht durch drei teilbar (Rest eins") else: print(zahl,"- ist nicht durch drei teilbar (Rest zwei")
# Autor: Christian Graf# Datum: 22.03.2011# Beschreibung: Ausgabe aller maximal zweistelligen Zahlen mit# # Zusatzinformation ueber den Rest der Division durch 3for zahl in range(100): if (zahl % 3 == 0): print(zahl,"- ist durch drei teilbar") elif (zahl % 3 == 1): print(zahl,"- ist nicht durch drei teilbar (Rest eins") elif (zahl % 3 == 2): print(zahl,"- ist nicht durch drei teilbar (Rest zwei")
Die beiden Realisierungen unterscheiden sich durch die Ausnutzung des else-Teiles bzw. die Angabe einer weiteren Bedingung. Zu beachten ist hier, dass eine der drei angegebenen Bedingungen immer wahr ist. Der Rest einer entsprechenden Division kann nur 1, 2 oder 0 sein.
Die einzelnen Möglichkeiten der Verzweigung werden auch Zweige genannt. Es können beliebig viele Zweige hinterlegt werden. Beispielsweise Bedingungen und Verzweigungen für alle Divisionsreste durch 100. Bei entsprechend komplexen Verzweigungen und Bedingungen muss man allerdings sehr genau auf die Wahl der Bedingung und auch deren Reihenfolge achten. Eine häufige Fehlerquelle bei komplexeren Bedingungen ist, dass man übersieht, dass gleichzeitig noch eine andere Bedingung erfüllt ist. So wird unter Umständen ein anderer - nicht beabsichtigter - Anweisungsblock ausgeführt.
Verknüpfung von einzelnen Bedingungen
Bisher haben wir immer nur "einfache" Bedingungen betrachtet:
zahl == 3
zahl % 2 == 0
"a"=="A"
13 < = zahl
zahl % 3 == 0
Wir wollen nun eine Möglichkeit kennenlernen, zwei einzelne Bedingungen zu einer neuen Bedingung zu kombinieren.
Wir stellen uns vor, wir wollen eine bestimmte Ausgabe etc. erreichen, wenn der Wert einer Variablen
durch 2 und durch 3 ohne Rest teilbar ist.
glatt durch 2 oder durch 3 teilbar ist.
Die einzelnen Bedingungen, durch 2 bzw. durch 3 ohne Rest teilbar, können wir bereits umsetzen. Die entsprechende Kombination durch und bzw. oder ist neu. Dafür gibt es in Python ebenfalls reservierte Wörter, um die entsprechenden (Teil-)Bedingungen zu verknüpfen.
Verbindet man zwei Bedingungen durch das Schlüsselwort and (und) so ist die gesamte Bedingung nur wahr, wenn die beiden verbundenen Bedingungen wahr sind.
Verbindet man zwei Bedingungen durch das Schlüsselwort or (oder) so ist die gesamte Bedingung wahr, sobald mindestens eine der beiden verbundenen Bedingungen wahr ist. In vielen Programmiersprachen wird dann die zweite Bedingung meist gar nicht mehr geprüft, wenn die erste Bedingung bereits erfüllt ist.
Zur besseren Lesbarkeit einigen wir uns darauf, dass wir um die einzelnen Bedingungen Klammern setzen. Entsprechend erhalten wir für unsere obigen Aussagen die folgenden Bedingungen:
Der Wert der Variablen zahl ist
durch 2 und durch 3 ohne Rest teilbar.
(zahl % 2 == 0) and (zahl % 3 == 0)
glatt durch 2 oder durch 3 teilbar.
(zahl % 2 == 0) or (zahl % 3 == 0)
Probiere es in der Shell aus! Beachte, dass du vorher der Variablen zahl einen Wert zuweisen musst. Probiere mit unterschiedlichen Werten für die Variable zahl, um so ein Gespür für die Kombination der beiden Verknüpfungen zu erhalten.
Auch die so konstruierten Bedingungen kann man weiter zu neuen Bedingungen kombinieren. Zu beachten ist aber, dass man in diesem Zusammenhang genau darauf achten muss, was man wie kombiniert. In bestimmten Fällen muss man wie in der Mathematik Klammern setzen. Ähnlich wie bei der Regel "Punkt- vor Strichrechnung" gibt es auch hier eine Regel, dass entsprechende Verknüpfungen mit and Vorrang haben.
Um die Konstruktion von Bedingungen vollständig zu machen, gibt es noch eine dritte Möglichkeit, neue Bedingungen zu konstruieren: Die sogenannte Negation. Die Bedingung not (zahl % 2 == 0) ist genau dann wahr, wenn die Bedingung (zahl % 2 == 0) falsch ist. Ergänzend ist die Bedingung not (zahl % 2 == 0) genau dann falsch, wenn die Bedingung (zahl % 2 == 0) wahr ist. not zählt ebenfalls zu den reservierten Wörtern. Vereinfacht kann man sagen: not kehrt den Wahrheitswert um.
Beispielprogramm:
# Autor: Christian Graf# Datum: 22.03.2011# Beschreibung: Ausgabe aller maximal zweistelligen Zahlen mit# # Zusatzinformation, ob die Zahl gerade ist oder eben nicht# # Verwendung der Negationfor zahl in range(100): if not(zahl % 2 == 0): print(zahl,"- ist nicht gerade") else: print(zahl,"- ist gerade")
Möchte man die entsprechende Negation hier nicht verwenden, so muss man die Zeilen 08 und 10 vertauschen. Erkennst du den Zusammenhang zum "Tauschen" des Wahrheitswertes durch die Negation und die beiden Teile der Verzweigung?
Zur Übung solltest du dir noch ein paar ähnliche Beispiele konstruieren, umsetzen und schließlich ausprobieren. Es bietet sich an, ggf. erstmal mit einem einfacheren Beispiel zu starten!
# Autor: Christian Graf# Datum: 22.03.2011# Beschreibung: Ausgabe aller maximal zweistelligen Zahlen mit# # Zusatzinformation, ob ...for zahl in range(100): if not((zahl % 3 == 0) and (zahl % 2 == 0)): print(zahl,"- ist nicht durch zwei und drei teilbar") else: print(zahl,"- ist durch zwei und drei teilbar")
Manchmal kann man Bedingungen auch vereinfachen bzw. zusammenfassen. Teilbar durch 2 und durch 3 impliziert, dass die Zahl durch 6 teilbar ist. Vielleicht erinnerst du dich an die Teilbarkeitsregeln, die du im Mathematikunterricht kennengelernt hast?
# Autor: Christian Graf# Datum: 22.03.2011# Beschreibung: Ausgabe aller maximal zweistelligen Zahlen mit# # Zusatzinformation, ob ...for zahl in range(100): if not(zahl % 6 == 0): print(zahl,"- ist nicht durch zwei und drei teilbar") else: print(zahl,"- ist durch zwei und drei teilbar")
Auch hier kann man wieder durch den Verzicht auf das reservierte Wort not - und damit den Verzicht auf die Negation - die beiden Verzweigungsblöcke tauschen.