.. include:: markup.rst ****************** Kontrollstrukturen ****************** Kontrollstrukturen helfen den :mark:`Ablauf eines Programms zu steuern`. Man unterscheidet: * Fallunterscheidungen (``if``, ``else``) und * Schleifen (``for``, ``while``) Fallunterscheidungen ==================== If, elif, else -------------- Die einfachste Möglichkeit der Fallunterscheidung ist die ``if`` - Anweisung. Diese sieht folgendermaßen aus: :: if Bedingung : # Anweisungskopf Anweisung # | ... # | Anweisungskörper Anweisung # | Diese besteht aus einem * :mark:`Anweisungskopf`, der eine :mark:`Bedingung` enthält und einem * :mark:`Anweisungskörper` (Codeblock) welcher je nach Ergebnis der Bedingung ausgeführt wird. Anders gesagt :mark:`WENN` Bedingung erfüllt, dann mach, was im Anweisungskörper steht. Z.B: :: if x < 1 : print("x kleiner 1") .. note:: * Der Anweisungskopf endet mit einem ``:``. * Der Anweisungskörper ist :mark:`eingerückt`! * Die gleiche Einrückung, wie das ``if`` bedeutet die Anweisung ist :mark:`außerhalb` des Anweisungskörpers! Die Abbildung `if-Anweisung grafisch`_ zeigt diese als Flußdiagramm. .. _`if-Anweisung grafisch`: .. figure:: images/ifAnweisung.jpg :scale: 60 % :align: center if-Anweisung grafisch Möchte man eine :mark:`weitere` Bedingung prüfen (wenn die erste ``False`` war), verwendet man eine ``elif`` - Anweisung. :: if Bedingung1 : # Pruefe Bed 1 Anweisung # | ... # | wenn Bed 1 True Anweisung # | elif Bedingung2 : # Pruefe Bed 2 Anweisung # | ... # | wenn Bed 2 True Anweisung # | Beispiel: :: if x < 1: print("x kleiner 1") elif x == 1: print("x gleich 1") Soll eine Anweisung ausgeführt werden wenn :mark:`keine der beiden Bedingungen` greift, verwendet man eine ``else`` - Anweisung. :: if Bedingung1 : # Pruefe Bed 1 Anweisung # | ... # | wenn Bed 1 True Anweisung # | elif Bedingung2 : # Pruefe Bed 2 Anweisung # | ... # | wenn Bed 2 True Anweisung # | else : # Sonst Anweisung # | ... # | wenn Bed 1 und 2 False Anweisung # | Beispiel: :: if x < 1: print("x kleiner 1") elif x == 1: print("x gleich 1") else: print("x ist groesser 1") Mit dieser Art der Fallunterscheidung lassen sich auch ``switch`` \ ``case`` Kontrollstrukturen (wie in Java oder C++) realisieren. Beispiel (``kontroll_switch.py``): Die Abbildung `if-elif-else-Anweisung grafisch`_ zeigt diese als Flußdiagramm. .. _`if-elif-else-Anweisung grafisch`: .. figure:: images/ifElifElseAnweisung.jpg :scale: 70 % :align: center if-elif-else--Anweisung grafisch .. literalinclude:: src/kontroll_switch.py Die häufigste Verwendung sind ``if``-``else`` Konstrukte (WENN - dann - SONST): :: if Bedingung : # Pruefe Bed Anweisung # | ... # | wenn True Anweisung # | else : # Sonst Anweisung # | ... # | wenn Bed False Anweisung # | .. hint:: Wenn möglich ``if`` Schleifen immer mit ``else`` versehen! Somit erkennt man Programmierfehler leichter. Schleifen ========= For - Schleifen --------------- Eine for-Schleife ist eine :mark:`Zählschleife`. Die Anzahl der Schleifendurchläufe kann mit dem :mark:`Schleifenzähler` angegeben werden: :: for Variable in Objekt : # nimm aus Obj eine Var Anweisung # | ... # | mach was damit Anweisung # | Beispiel (``kontroll_for.py``): .. literalinclude:: src/kontroll_for.py Ausgabe: :: 0 1 2 Die ``range(..)`` Funktion liefert dabei einen Iterator der mit ``list(..)`` in eine Liste umgewandelt werden kann. Z.B. : :: In [1]: range(3) # gibt einen Iterator zurueck Out[1]: range(0, 3) In [2]: list( range(3) ) # wandelt den Iterator in eine Liste um Out[2]: [0, 1, 2] Diese Funktion kann man ganz allgemein verwendet werden: :: In [3]: list( range(1,10,2) ) Out[3]: [1, 3, 5, 7, 9] In [4]: liste=[1,3,5] Listen kann man auf 2 Arten durchlaufen: :: In [5]: for l in liste : ...: print(l) ...: 1 3 5 In [6]: for i in range(len(liste)) : ...: print(i, liste[i]) ...: 0 1 1 3 2 5 je nach dem ob man den Index ``i`` benötigt oder nicht. Dictionaries durchläuft man z.B. mit: :: In [7]: dic = {0:"a", 3:"b", 6:"c" } In [8]: for key in dic: ...: print(key, dic[key]) ...: 0 a 3 b 6 c Die Abbildung `for Schleife grafisch`_ zeigt diese als Flußdiagramm. .. _`for Schleife grafisch`: .. figure:: images/forSchleife.jpg :scale: 70 % :align: center for Schleife grafisch While - Schleifen ----------------- Diese führen Codeblock so lange aus, wie eine bestimmte :mark:`Bedingung erfüllt` ist. :: while Bedingung : # solange Bed True Anweisung # | ... # | mach was damit Anweisung # | Das Flussdiagramm sieht wie bei Abbildung `for Schleife grafisch`_ aus. Beispiel (``kontroll_while.py``): .. literalinclude:: src/kontroll_while.py Ausgabe: :: Raten Sie: 1234 Raten Sie: 1543 Raten Sie: 1337 Sie haben es geschafft! Im :mark:`Vergleich` zur ``for`` Schleife kennt man bei der ``while`` Schleife die Anzahl der Schleifendurchläufe nicht! .. note:: Die ``input`` Anweisung liest dabei Zeichen von der Python Shell ein welche mit ``int(..)`` in Zahlen umgewandelt werden. Mit ``ENTER`` bestätigt man diese Eingabe. .. warning:: While Schleifen sind gefährlich! Schlechte Programmierung kann zu :mark:`Endlosschleifen` führen. Dann hilft manchmal nur mehr ein :mark:`Programmabbruch` ... Vorzeitiger Abbruch eines Schleifendurchlaufs --------------------------------------------- Es gibt Möglichkeiten den Ablauf einer Schleife zu beeinflussen. * ``break`` Anweisung: beendet den :mark:`gesamten` Schleifendurchlauf, verläßt die Schleife. * ``continue`` Anweisung: beendet den :mark:`aktuellen` Schleifendurchlauf, startet den nächsten Durchlauf. Schematisch sieht dies so aus: :: while Bedingung : # <- ... # | if Bedingung1: # | springt nach oben continue # -- ... if Bedingung2: # break # -- ... # | springt nach unten ... # <- Beispiel (``kontroll_while_break_continue.py``): .. literalinclude:: src/kontroll_while_break_continue.py Ausgabe: :: Positive Zahl eingeben : 22 Zahl = 22 Positive Zahl eingeben : -3 Negative Zahlen nicht erlaubt! Positive Zahl eingeben : 6 Zahl = 6 Positive Zahl eingeben : 0 Skript wird beendet! Die pass Anweisung ================== Während der Entwicklung eines Programms kommt es vor, dass * eine Kontrollstruktur vorerst nur :mark:`teilweise implementiert` wird. * Der Anweisungskopf wird erstellt, es :mark:`fehlt` jedoch der :mark:`Anweisungskörper`. * Ein fehlender Anweisungskörper wäre aber ein Syntaxfehler. * :mark:`Abhilfe` schafft dabei die ``pass`` Anweisung. Beispiel: :: if x == 1: pass # wird später implementiert elif x == 2: print("x hat den Wert 2") else : print("Weder 1 noch 2.") .. Iteratoren ---------- Eine weitere Methoden :mark:`Sequenzen durchzulaufen` sind Iteratoren. Ein Beispiel sieht z.B. so aus: :: >>> a = [1,2,3] >>> i = iter(a) >>> i.next() 1 >>> i.next() 2 >>> i.next() 3 Übungsbeispiele ================== **Aufgabe 4.1** Gegeben ist ein String, der beliebig viele Zahlen enthält, die durch Strichpunkte getrennt sind. Aus diesem String sollen die Zahlen extrahiert werden und in Dictionary eingefügt werden, wobei die Zahl als String der Schlüssel und die Zahl als Typ ``float`` der Wert sein soll. Ein guter Programmierstil zeichnet sich dadurch aus, dass möglichst jede Annahme, die über Eingaben getroffen wird, überprüft wird, damit das Programm nicht abstürzt. Aus diesem Grund ist es wichtig zu überprüfen,... 1) ...ob es sich bei der Eingabe tatsächlich um einen String handelt. 2) ...ob die extrahierten Zahlen tatsächlich Zahlen sind. 3) ...ob der neue Schlüssel bereits im Dictionary enthalten ist. Neue Schlüssel sollen erst dann zum Dictionary hinzugefügt werden, wenn sie noch nicht im Dictionary enthalten sind. Geben Sie mittels ``print`` eine Warnung aus, wenn Punkt 1), 2) oder 3) nicht erfüllt werden. **Aufgabe 4.2** Definieren Sie eine beliebige positive, ganze Zahl ``Testzahl``. Überprüfen Sie, ob es sich bei dieser ``Testzahl`` um eine Primzahl handelt. Geben Sie ``True`` aus, wenn ``Testzahl`` eine Primzahl ist, bzw. ``False``, wenn nicht. .. hint :: Dazu kann z.B. ein ganz primitiver Algorithmus verwendet werden, bei dem zunächst eine untere und obere Schranke für die möglichen Teiler der ``Testzahl`` festgelegt werden und dann für alle Zahlen in diesem Intervall überprüft wird ob sie Teiler von ``Testzahl`` sind. Testen Sie Ihre Funktion an einigen Zahlen, z.B. * keine Primzahlen: 323, 1, ... * Primzahlen: 2, 43, 97, ... .. hint :: 1 ist keine Primzahl. Beachten Sie bei Verwendung von ``range``, dass die obere Grenze nicht angenommen wird! weitere Übungsbeispiele ================= **Aufgabe 4.3** Gegeben ist ein Dictionary ``Woerterbuch``, dass als Schlüssel deutsche Wörter und als Werte die entsprechende Übersetzung ins Englische enthält. Z.B. ``'gruen': 'green', 'eines': 'a', 'Gras': 'gras', 'ist': 'is', 'eine': 'a', 'das': 'the', 'ein': 'a'``. 1) Erstellen Sie ein 2. Dictionary ``Woerterbuch_ende``, dass die englischen Wöerter als Schlüssel und die deutschen Wörter als Werte enthält. 2) Ändern Sie Ihre Lösung zu 1), sodass eine Fehlermeldung ausgegeben wird, wenn ein englisches Wort bereits in ``Woerterbuch_ende`` enthalten ist. 3) Erweitern Sie Ihre Lösung zu 2). Wenn zu einem englischen Wort (z.B. ``a``) mehrere deutsche Übersetzungen in ``Woerterbuch`` enthalten sind (z.B. ``ein, eine``), wird in ``Woerterbuch_ende`` das englische Wort als Schlüssel und eine Liste aller deutschen Übersetzungen als Wert eingefügt. **Aufgabe 4.4** Definieren Sie eine Zeichenkette beliebiger Länge. Bestimmen Sie die Anzahl der Vokale (a,e,i,o,u) in diesem String und geben sie diese aus. Testen Sie Ihr Skript an beliebigen Zeichenketten. .. hint :: Verwenden Sie ``for..in..`` und ``if..in..``.