Tutorial:Programmieren mit Python/Kontrollstrukturen: Unterschied zwischen den Versionen

Aus KGS-Wiki
K (Link gefixt)
Zeile 113: Zeile 113:
| INHALT = <mermaid>
| INHALT = <mermaid>
graph TD
graph TD
start["..."] --> teile["Teil E"] --> teila
start["..."] --> teile["Teil E"] --> teile
</mermaid>
</mermaid>
}}
}}

Version vom 8. April 2024, 23:17 Uhr

Bedingte Verzweigung (if, elif, else)

Zur Realisierung einer Fallunterscheidung werden in Python die Schlüsselworte if, elif und else genutzt.

Bedingte Anweisung mit if

graph TD start["..."] --> if{"Bedingung"} -- ja --> teila["Teil A"] --> ende["..."] if -- nein --> ende

Der einfachste Fall ist eine Sequenz von Anweisungen, die nur dann ausgeführt werden soll, wenn eine bestimmte Bedingung erfüllt ist, sonst nicht. Die Schreibweise ist if Bedingung: und dann folgen die Anweisungen, die in dem Fall ausgeführt werden sollen, dass die Bedingung wahr ist. Diese Anweisungen müssen eingerückt werden, damit der Interpreter identifizieren kann, welche Anweisungen in Abhängigkeit von der Bedingung und welche immer ausgeführt werden sollen.

Im folgenden Beispiel wird die print-Anweisung nur ausgeführt, falls der Ausdruck (notendurchschnitt > 4) zu wahr (True) ausgewertet wird:

if notendurchschnitt > 4.0:
    # Teil A
    print('Die Klausur muss von der Schulleitung genehmigt werden.')

Bedingungen

Als Bedingung kann jeder Ausdruck eingesetzt werden, der zu True oder False ausgewertet werden kann. Hier werden also in der Regel logische Ausdrücke verwendet, zum Beispiel Vergleiche mit den Vergleichsoperatoren < (kleiner als), > (größer als) oder == (gleich).

Mehrere Vergleiche lassen sich mit den logischen Verknüpfungsoperatoren and (logisches UND) und or (logisches ODER) zu einer Bedingung verknüpfen. Im folgenden Beispiel wird die print-Anweisung ausgeführt, falls der Wert der Variablen notendurchschnitt größer als 4 oder kleiner als 1.5 ist (d. h. wenn mindestens einer der mit or verknüpften Vergleiche wahr ist):

if notendurchschnitt > 4.0 or notendurchschnitt < 1.5:
    # Teil A
    print('Die Klausur muss von der Schulleitung genehmigt werden.')

Werden Vergleiche dagegen mit and verknüpft, müssen alle einzelnen Vergleiche zu wahr ausgewertet werden, damit die Gesamtbedingung wahr ist:

if notendurchschnitt > 4.0 and anzahl_klausuren >= 2:
    # Teil A
    print('Die Klausur muss von der Schulleitung genehmigt werden.')</code>

Alternative mit else

graph TD start["..."] --> if{"Bedingung"} -- ja --> teila["Teil A"] --> ende["..."] if -- nein --> teilB["Teil B"] --> ende

Um alternative Anweisungen auszuführen, wenn die Bedingung nicht erfüllt ist, wird das Schlüsselwort else: (engl. sonst) verwendet. Das else wird im Gegensatz zu den Anweisungen für den Dann- und den Sonst-Fall nicht eingerückt, steht also auf derselben Einrückungstiefe wie das if.

if notendurchschnitt > 4.0:
    # Teil A
    print('Die Klausur muss von der Schulleitung genehmigt werden.')
else:
    # Teil B
    print('Alles okay, die Klausur kannst du problemlos zurückgeben.')</code>

Mehrfache bedingte Verzweigung mit elif

graph TD start["..."] --> if1{"Bedingung"} -- ja --> teila["Teil A"] --> ende["..."] if1 -- nein --> if2{"Bedingung"} -- ja --> teilB["Teil B"] --> ende if2 -- nein --> teilc["Teil C"] --> ende

Mit elif (kurz für else if) können mehrere Bedingungen nacheinander abgeprüft werden. In diesem Fall werden die Bedingungen solange abgeprüft, bis eine davon wahr ist. Nur die Anweisungen, die zu dieser Bedingung gehören werden dann ausgeführt.

Nach einem if können beliebig viele elifs folgen. Für den Fall, dass gar keine der abgeprüften Bedingungen wahr ist, kann nach den elifs ein else folgen.

if notendurchschnitt > 4.0:
    # Teil A
    print('Die Klausur muss von der Schulleitung genehmigt werden.')
elif notendurchschnitt > 2.0:
    print('Na, das ist doch ganz okay gelaufen.')
else:
    # Teil C
    print('Wow, das ist ja ein Hammer-Durchschnitt!')

Im obigen Beispiel würde ein Notendurchschnitt von 4.2 beide Bedingungen erfüllen, aber es würde nur der Text "Die Klausur muss von der Schulleitung genehmigt werden." ausgegeben werden, da die Auswertung nach dem ersten Auffinden einer erfüllten Bedingung endet.

Bedingte Wiederholung (while)

graph TD start["..."] --> while{"Bedingung"} -- ja --> teild["Teil D"] --> while -- nein --> ende["..."]

Um eine Anweisung oder eine Sequenz von Anweisungen in Abhängigkeit von einer Bedingung zu wiederholen, nutzen wir das Schlüsselwort while, welches genau so genutzt wird wie if: nach dem while folgt eine Bedingung, die erfüllt sein kann oder nicht, danach folgen, eingerückt, die Anweisungen, die so lange ausgeführt werden sollen, wie die Bedingung erfüllt ist.

Im folgenden Beispiel soll der Nutzer seine Postleitzahl eingeben. Die Eingabe wird geprüft und die Eingabeaufforderung wiederholt, solange wie keine Zahl eingegeben wurde:

plz = input('Bitte geben Sie Ihre Postleitzahl ein: ')
while not plz.isnumeric():
    # Teil C
    plz = input('Das ist keine Zahl. Bitte versuchen Sie es erneut: ')
⚠️
Achtung

Anders als in Scratch werden hier die Anweisungen nicht wiederholt, bis die Bedingung wahr ist, sondern solange sie wahr ist. Die folgenden Code-Schnipsel sind äquivalent:

while x >= 1:
    x = x - 1
    print(x)</code>
wiederhole bis <(x) < [1]>
ändere [x v] um [-1]
sage (x)
ende

graph TD start["..."] --> teile["Teil E"] --> teile

Eine endlos laufende Wiederholung lässt sich realisieren, indem nach dem while eine immer wahre Bedingung gestellt wird:

while True:
    # Teil C
    print('Diese Wiederholung läuft ewig.')
   
while 1 == 1:
    # Teil C
    print('Diese theoretisch auch - praktisch wird sie nie gestartet, weil die Wiederholung davor endlos läuft.')

Auch eine endlos laufende Wiederholung kann aber mit dem Schlüsselwort break unterbrochen werden. Wenn mehrere Wiederholungen ineinander geschachtelt werden, wird dabei nur die innerste unterbrochen, in der sich die break-Anweisung befindet.

Dies kann vor allem nützlich sein, wenn die Abbruchbedingung der Wiederholung sehr komplex oder mehrstufig ist. In folgendem Beispiel soll der Nutzer seine Postleitzahl eingeben. Die Eingabe wird in zwei Schritten auf Korrektheit überprüft: zuerst wird mit isnumeric() geprüft, ob der eingegebene String plz nur aus Ziffern besteht; falls dies der Fall ist, wird überprüft, ob die eingegebene Zahl zwischen 01001 und 99998 liegt und damit eine gültige deutsche Postleitzahl sein könnte. Hierbei wird die Eingabe in ein int konvertiert, was bei einer nicht-numerischen Eingabe zu einer Fehlermeldung und dem Abbruch des Programms führen würde.

while True:
    plz = input('Bitte geben Sie Ihre Postleitzahl ein: ')
    if not plz.isnumeric():
        print('Sie haben keine Zahl eingegeben.')
    elif int(plz) < 1001 or int(plz) > 99998:
        print('Das ist keine gültige Postleitzahl.')
    else:
        break

Wiederholungen über eine Datenstruktur (for)

Das Schlüsselwort for kann man benutzen, um für alle Elemente in einer Datenstruktur dieselben Anweisungen auszuführen. Das kann eine Liste sein, ein String oder ähnliches. Die Syntax der Wiederholung ist for Element in Liste[1]: und danach folgen die Anweisungen, wieder eingerückt.

klassenliste = ['Max','Moritz','Paul','Paula','Enno','Enna','Jakob','Johannes','Lukas','Mats']
print('Moin. Wer fehlt heute?')
for kind in klassenliste:
    print(kind + ', bist du da?')

Wiederholungen mit fester Anzahl (range)

Für eine Wiederholung mit fester Anzahl, wie sie aus Scratch bekannt ist, kann die Datenstruktur range benutzt werden. Eine range zählt dabei von einem ggf. vorgegebenen Startwert zu einem vorgegebenen Endwert mit einer ggf. ebenfalls vorgegebenen Schrittweite hoch. Dies kann für eine for-Wiederholung genutzt werden. Der range können dabei bis zu drei Parameter übergeben werden:

  • ein Startwert, von wo die range zu zählen beginnen soll, dieser ist optional und wird standardmäßig auf 0 gesetzt
  • ein Endwert, bei dem die range aufgehört haben soll, zu zählen, dieser muss auf jeden Fall angegeben werden.
  • eine Schrittweite, die beim Zählen eingesetzt werden soll, diese ist optional und wird standardmäßig auf 1 gesetzt. Wenn die range rückwärts zählen soll, muss eine negative Schrittweite eingesetzt werden. Die Schrittweite darf nicht auf 0 gesetzt werden.

Wird nur ein Parameter übergeben, wird dieser als Endwert interpretiert, zwei Parameter werden als Start- und Endwert interpretiert.

Der übergebene Endwert wird nicht mitgezählt! Eine range(0,5) zählt also nur bis 4!

Betrachten wir das Verhalten einiger ranges:

>>> list(range(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list(range(3,7))
[3, 4, 5, 6]
>>> list(range(2,18,3))
[2, 5, 8, 11, 14, 17]
>>> list(range(3,-4,-1))
[3, 2, 1, 0, -1, -2, -3]

Eine for-Wiederholung in Verbindung mit einer range lässt sich wie folgt als while-Wiederholung darstellen:

for x in range(start,finish,step):
    do_some_stuff_with(x)

entspricht:[2]

x = start
while x < finish:
    do_some_stuff_with(x)
    x = x + step

Dass der Endwert, der einer range übergeben wird, nicht mitgezählt wird, hat durchaus Vorteile. Zum Beispiel kann man so die Länge einer Liste an eine range übergeben, die dann durch alle Indizes der Liste von 0 bis Länge-1 hochzählt.

  1. Statt einer Liste kann jede beliebige Datenstruktur verwendet werden, die iterierbar (engl. iterable) ist, d. h. es zulässt, eine Menge an Elementen in einer gewissen Reihenfolge durchzugehen.
  2. Der Einfachheit und Lesbarkeit halber ist die while-Wiederholung hier nur für positive Schrittweiten dargestellt. Überleg mal: wie müsste man die Bedingung der while-Wiederholung anpassen, damit sie auch für negative Schrittweiten funktionieren würde?