Programmflusskontrolle

Logische Variablen

Manche Aussagen sind wirklich wahr...

  • 1 ist gleich 1.
  • Impfen hilft.
  • Maik ist ein alter Sack.

... und andere schlicht falsch:

  • 1 ist gleich 2.
  • Die Erde ist eine Scheibe.

Dafür gibt es in Python und anderen Programmiersprachen einen eigenen Datentyp, die Boole'sche (nach G. Boole) oder logische Variablen genannt werden. Dieser Datentyp kennt nur zwei Werte: True und False.

Bool'sche Variable werden z.B. aus Vergleichsoperationen erzeugt:

In [1]:
# Vergleich von Zahlenwerten
7 > 2 
Out[1]:
True
In [2]:
7 < 2 
Out[2]:
False
In [3]:
# Vergleich von Zeichenketten
"Golm" == "Potsdam"
Out[3]:
False

Zur Erinnnung: Der Test auf Gleichheit erfordert das doppelte Gleichheitszeichen ==.

In [4]:
# Vergleich von Zahlen auf Ungleichheit
5 != 1
Out[4]:
True

Die Ergebnisse derartiger Vergleiche kann man wiederum in logischen Variablen speichern, um später darauf zurückzugreifen:

In [5]:
temperatur = -5.
esfriert = (temperatur <= 0.)
print("Es friert:", esfriert)
print(type(esfriert))
Es friert: True
<class 'bool'>

Logische Operationen

Mit logischen Variablen lässt sich eine ganze Menge an 'logischer Arithmetik' betreiben:

In [6]:
istnass = True
# logisches UND: nur wahr, wenn beide Seiten wahr sind
istglatt = istnass and esfriert
istglatt
Out[6]:
True

Das Resultat ist nur True, wenn beide Seiten auch True sind, sonst False.

In [7]:
zuschnell = False
#logisches ODER, auch wahr, wenn beide Seiten wahr sind
unfall = istglatt or zuschnell  
unfall
Out[7]:
True

Aufgabe: Wahrheitswerte

Welche Wahrheitswerte haben folgende Ausdrücke? Versuche erst, sie im Kopf auszuwerten, dann die Ausdrücke in Python zu formulieren und das Ergebnis zu überprüfen.

Es sei A = WAHR, B = FALSCH.

1. A und (nicht(B))
2. nicht (nicht(A))
3. nicht(A) oder nicht(B)

Lösung - im Kopf gelöst

  1. WAHR
  2. WAHR
  3. WAHR

Lösung - Python Code

In [8]:
A = True
B = False
In [9]:
#1.
A and not B
Out[9]:
True
In [10]:
#2.
not(not A)
Out[10]:
True
In [11]:
#3.
(not A) or (not B)
Out[11]:
True

Programmflusskontrolle A: Bedingungen mit if

Logische Ausdrücke bzw. Variablen sind unverzichtbar für Fallunterscheidungen, wie in wenn-dann-Beziehungen:

  • Wenn es regnet, dann nimm den Regenschirm mit.
  • Wenn der Dataframe eine Spalte namens "temp" hat, dann erzeuge einen Plot davon.
  • Wenn Dich die bösen Buben locken, dann bleib zu Haus und stopfe Socken.

In Python sieht das folgendermaßen aus:

In [12]:
regenwetter = True
if regenwetter:
    print("Regenschirm einpacken!")
Regenschirm einpacken!

Nach dem if steht also ein Ausdruck, der einer logischen Variable entspricht, also den Wert True oder False annimmt. Falls der Ausdruck True ist, wird wird die folgende, eingerückte Zeile ausgeführt. Das Ganze kann auch deutlich komplizierter aufgebaut sein:

In [13]:
regenwetter = True
warmer_sommerregen = False
unterwegs_zur_regenschirmtauschboerse = False
if ((regenwetter and not warmer_sommerregen) or unterwegs_zur_regenschirmtauschboerse):
    print("Regenschirm einpacken!")
Regenschirm einpacken!

Die Konstruktion kann außerdem um eine Aktion ergänzt werden, die im nicht-zutreffenden Fall ausgeführt wird:

In [14]:
regenwetter = False
if regenwetter:
    print("Regenschirm einpacken!")
else:
    print("Schirm bleibt zu Hause!")
Schirm bleibt zu Hause!

Hier wird also immer nur die erste ODER die zweite Anweisung ausgeführt.
Derartige Konstruktionen kann man mit Aktivitätsdiagrammen darstellen, die etwa so aussehen können: Aktivitätsdiagramm

Diese können insbesondere bei komplexeren Fällen hilfreich sein.

Aufgabe: Sonnencreme

Jetzt wollen wir bei gutem Wetter nicht nur den Regenschirm zu Hause lassen, sondern auch noch die Sonnencreme einpacken. Wie muss der Code oben erweitert werden?

Lösung

In [15]:
regenwetter = True
if regenwetter:
    print("Regenschirm einpacken!")
else:
    print("Schirm bleibt zu Hause!")
    print("Sonnencreme einpacken!")
Regenschirm einpacken!

Eine sorgfältige Formatierung des Quelltextes durch entsprechende Einrückungen ist in Python zwingend notwendig. Dies erleichtert auch die Lesbarkeit des Programmcodes erheblich. In den meisten Editoren gibt es einen Shortcut um ganze Code-Blöcke einzurücken, oder wieder zurück zu rücken. Hier ist es Sektion markieren + Tab, bzw. Sektion markieren + Shift+Tab


Wenn es nicht gerade "alternativlos" ist, gibt es im richtigen Leben manchmal ja auch mehr als zwei Alternativen. Wir könnten unsere Tagesaustattungb z.B. je nach Wetterlage zwischen Pudelmütze, Regenschirm und Sonnencreme wählen:

In [16]:
wetter = "sonnig" #hier "frostig", "regnerisch" oder "sonnig" wählen
if (wetter == "frostig"):
        print("Pudelmütze eingepackt!")
  
elif (wetter == "regnerisch"):  #elif heißt else if
    print("Regenschirm eingepackt!")
    
elif (wetter == "sonnig"):
  print("Sonnencreme eingepackt!")

else: 
    print("Nichts eingepackt.")
Sonnencreme eingepackt!

Die haben wir also drei Fälle abgedeckt und sogar an eine vierte Variante gedacht, falls keiner der drei Fälle zutrifft, also für alle anderen Werte von wetter.

Logische Aggregatoren

Manchmal möchte man eine Bedingung prüfen, die vom Vergleich mehrerer Werte abhängt.

Aufgabe: Frost

So könnten wir uns z.B. fragen, ob es während einer einer Woche Frost gegeben hat, also die Zeitreihe der Minimaltemperaturdaten tmin = [2, 1, 0, -1, 3, 2, 4] mindestens einmal unter 0 °C gefallen ist.

Wie könnte man diese Frage mit den bisher bekannten Mitteln beantworten?

Lösung

In [17]:
tmin = [2, 1, 0, -1, 3, 2, 4]
frost = tmin[0]<0 or tmin[1]<0 or tmin[2]<0 or tmin[3]<0 or tmin[4]<0 or tmin[5]<0 or tmin[6]<0
frost
Out[17]:
True

Diese Lösung ist allerdings sehr unelegant. Wir müssen viel tippen, und die Lösung nur, solange wir genau sieben Werte im Vektor tmin haben. Ein achter Wert würde bei der Prüfung nicht berücksichtigt.

Aggregierung mit any und all

Hier werden die logischen Aggregierungsfunktionen any und all nützlich. Diese prüfen, ob in einem Array/Vektor von logischen Variablen mindestens ein Eintrag (any) bzw. alle Einträge (all) True sind: Um alle Einträge einer Liste auf einmal zu berücksichtigen, müssen die Listen vorher in Numpy-Arrays umgewandelt werden. Dies spart letztendlich sehr viel Arbeit.

In [18]:
all([True, False])
Out[18]:
False
In [19]:
any([True, False])
Out[19]:
True
In [20]:
import numpy
In [21]:
# Liste mit Minimumtemperaturen
tmin = [2, 1, 0, 1, 3, 2, 4, -1]
# numpy array
tmin = numpy.array(tmin)
type(tmin)
Out[21]:
numpy.ndarray
In [22]:
frosttage = tmin < 0

frost = any(frosttage) 
nurfrost = all(frosttage) 

print("Wenigstens EIN Frosttag:", frost)
print("NUR Frosttage:", nurfrost)
Wenigstens EIN Frosttag: True
NUR Frosttage: False

Mit dieser Umsetzung funktioniert der Code nun auch mit beliebig langen Datenreihen.

Verkettung logischer Vektoren

Wir haben mit der Variablen frosttage einen Numpy-Array von Wahrheitswerten erzeugt, der für jeden Tag die Information enthält, ob es Frost gab:

In [23]:
tmin = [2, 1, 0, 1, 3, 2, 4, -1]
tmin = numpy.array(tmin)
frosttage = tmin < 0
frosttage
Out[23]:
array([False, False, False, False, False, False, False,  True])

Man kann nun auch mehrere derartiger Vektoren benutzen, um mehrteilige Bedingungen zu prüfen. Dafür müssen wir die Listen in Numpy-Arrays umwandeln und folgende Operatoren benutzen & (statt and) und |(statt or):

In [24]:
A = numpy.array([True, False, True,  False]) 
B = numpy.array([True, True,  False, False]) 
In [25]:
# Elementweises UND
A & B
Out[25]:
array([ True, False, False, False])
In [26]:
# Elementweises ODER
A | B 
Out[26]:
array([ True,  True,  True, False])
In [27]:
# Elementweises Negieren
~A
Out[27]:
array([False,  True, False,  True])

Achtung: &, | und ~ funktionieren nur bei numpy-Arrays. Sonst heißt es and, or und not!

In [28]:
not True
Out[28]:
False
In [29]:
~numpy.array([True])
Out[29]:
array([False])

Aufgabe Schnee I

Nun haben wir neben den Temperaturdaten auch eine Niederschlagszeitreihe. Wir nehmen an, dass an Frosttagen mit Niederschlag Schnee gefallen sein könnte. Gab es Schneefall im betrachteten Zeitraum?

In [30]:
tmin = numpy.array(        [2, 1, 0, 1, 3, 2, 4, -1])
niederschlag = numpy.array([0, 0, 3, 2, 0, 0, 0,  3])

Lösung

In [31]:
tage_mit_frost = tmin < 0
tage_mit_niederschlag = niederschlag > 0
 
tage_mit_schnee = tage_mit_frost & tage_mit_niederschlag
any(tage_mit_schnee)
Out[31]:
True

Aufgabe Schnee II

Wieviele Schneetage gab es? An welchen Tagen genau fiel der Schnee? Wie hoch ist die Summe des als Schnee gefallenen Niederschlags?

Hinweis

Da True und False in Python wie 1 und 0 behandelt werden, ist die Funktion sum() hier hilfreich. Um zu bestimmen, welche Elemente eines Vektors von Wahrheitswerten True sind, verwende die Funktion numpy.where().

Lösung

In [32]:
# Wieviele Schneetage gab es?
sum(tage_mit_schnee)
Out[32]:
1
In [33]:
# An welchen Tagen hat es geschneit?
numpy.where(tage_mit_schnee)
Out[33]:
(array([7], dtype=int64),)
In [34]:
# Niederschlagssumme der Schneetage
sum(niederschlag[tage_mit_schnee])
Out[34]:
3

Programmflusskontrolle B: Schleifen mit for

Die naive Lösung der Frost-Aufgabe ist ein Beispiel für die Wiederholung von (nahezu) identischen Kommandos. Neben zusätzlichem Schreibaufwand birgt derartiges Vorgehen immer die Gefahr zusätzlicher Fehler. Außerdem sind Anpassungen im Code mit viel Aufwand verbunden.

Dies spiegelt sich in der Programmiermaxime "Don't repeat yourself!" (DRY) wider. Vermeide Wiederholungen von Code! Use 'Style & Taste', not 'Copy & Paste'! Gegenteilige Lösungen werden auch als WET ("write everything twice" / "write every time" / "we enjoy typing" / "waste everyone's time") bezeichnet. Mögen diese anfangs schneller geschrieben und in Einzelfällen auch besser lesbar sein, überwiegen i.d.R. doch die Vorteile von DRY.

Beispiel Schneefegen

Gegeben sei ein Vektor von Tagen, an denen Schnee fällt tage_mit_schnee. Es soll nun für jeden Tag ausgegeben werden, ob wir aufstehen müssen, um Schnee zu fegen... oder ausschlafen können. Ein WET-Lösung könnte so aussehen:

In [35]:
tage_mit_schnee = [False, False, True, False, True, True, True]
In [36]:
if tage_mit_schnee[0]:
    print("Tag 1: Schneefegen!")
else:
    print("Tag 1: Ausschlafen!")
if tage_mit_schnee[1]:
    print("Tag 2: Schneefegen!")
else:
    print("Tag 2: Ausschlafen!")
if tage_mit_schnee[2]:
    print("Tag 3: Schneefegen!")
else:
    print("Tag 3: Ausschlafen!")
if tage_mit_schnee[3]:
    print("Tag 4: Schneefegen!")
else:
    print("Tag 4: Ausschlafen!")
if tage_mit_schnee[4]:
    print("Tag 5: Schneefegen!")
else:
    print("Tag 5: Ausschlafen!")
if tage_mit_schnee[5]:
    print("Tag 6: Schneefegen!")
else:
    print("Tag 6: Ausschlafen!")
if tage_mit_schnee[6]:
    print("Tag 7: Schneefegen!")
else:
    print("Tag 7: Ausschlafen!")
Tag 1: Ausschlafen!
Tag 2: Ausschlafen!
Tag 3: Schneefegen!
Tag 4: Ausschlafen!
Tag 5: Schneefegen!
Tag 6: Schneefegen!
Tag 7: Schneefegen!

Ziemlich viel redundanter Code - ein klassischer Fall für eine for-Schleife:

In [37]:
tage_mit_schnee = [False, False, True, False, True, True, True]

# range erzeugt hier eine Sequenz von 0 bis AUSSCHLIEßLICH 7
for zaehler in range(0,7):
    # aus dieser Sequenz wählt "for" nacheinander aus und weist den Wert "zahler" zu 
    if (tage_mit_schnee[zaehler]):
        print("Tag " + str(zaehler + 1) + ": Schneefegen!")
    else:
        print("Tag " + str(zaehler + 1) + ": Ausschlafen!")
Tag 1: Ausschlafen!
Tag 2: Ausschlafen!
Tag 3: Schneefegen!
Tag 4: Ausschlafen!
Tag 5: Schneefegen!
Tag 6: Schneefegen!
Tag 7: Schneefegen!

Aktivitätsdiagramm for-Schleife

Fein! Sollten wir uns nun entscheiden, statt Schnee zu fegen, liegenzubleiben, müssen wir das lediglich an einer einzigen Stelle im Code ändern.

Aufgabe: Schneefegen I

Die Zeitreihe der Schneetage sei nun von unbekannter, d.h. variabler Länge. Passe die Schleife so an, dass sie für beliebig lange Zeitreihen funktioniert!

In [38]:
# Mit diesem Modul lassen sich Zufallszahlen generieren
import random
In [39]:
# Hier wird k-mal aus den Optionen True oder False gewählt
tage_mit_schnee = random.choices([True,False], k=random.randint(1, 30))

Hinweis

In der for-Schleife folgt nach dem Schlüsselwort in eine Sequenz (ähnlich einem Vektor), dessen Elemente "iteriert" (abgearbeitet) werden, hier also range(0,7), also von 0 bis 6. Sollte unser Vektor tage_mit_schnee nun eine andere Länge aufweisen, kann man diese ja mit len() bestimmen (length)...

Lösung

In [40]:
tage_mit_schnee = random.choices([True,False], k=random.randint(1, 30))

for zaehler in range(0,len(tage_mit_schnee)):
    if tage_mit_schnee[zaehler]:
        print("Tag " + str(zaehler + 1) + ": Schneefegen!")
    else:
        print("Tag " + str(zaehler + 1) + ": Ausschlafen!")
Tag 1: Schneefegen!
Tag 2: Ausschlafen!
Tag 3: Schneefegen!
Tag 4: Schneefegen!
Tag 5: Schneefegen!
Tag 6: Ausschlafen!
Tag 7: Ausschlafen!
Tag 8: Ausschlafen!

Optionale Aufgabe (Vertiefung): Schneefegen II

Wir bekommen einen neuen Mitbewohner in unserem Haus und sind nur noch an ungeraden Tagen verantwortlich. Passe die Schleife durch

a) Veränderung des Schleifenkopfs oder
b) durch Veränderung des Schleifenkörpers an!

Hinweis

Auch hier hilft es, den zu iterierenden Vektor im letzten Teil der for-Konstruktion zu verändern. Der range()-Befehl bietet da vielfältige Möglichkeiten...

Lösung a)

In [41]:
tage_mit_schnee = random.choices([True,False], k=random.randint(1, 30))

for zaehler in range(0,len(tage_mit_schnee),2):
    if tage_mit_schnee[zaehler]:
        print("Tag " + str(zaehler + 1) + ": Schneefegen!")
    else:
        print("Tag " + str(zaehler + 1) + ": Ausschlafen!")
Tag 1: Ausschlafen!
Tag 3: Ausschlafen!
Tag 5: Schneefegen!
Tag 7: Schneefegen!
Tag 9: Schneefegen!
Tag 11: Ausschlafen!

Hinweis

Ob eine Zahl gerade oder ungerade ist, kann man mit dem Modulo-Operator % ermitteln. Dieser gibt den jeweiligen Rest bei ganzzahliger Division zurück. So ist 8 % 3 gleich 2, denn wenn man 8 durch 3 teilt, bleibt der Rest 2

Lösung b)

In [42]:
for zaehler in range(0,len(tage_mit_schnee)):
    if (zaehler % 2 == 0):
        if tage_mit_schnee[zaehler]:
            print("Tag " + str(zaehler + 1) + ": Schneefegen!")
        else:
            print("Tag " + str(zaehler + 1) + ": Ausschlafen!")
Tag 1: Ausschlafen!
Tag 3: Ausschlafen!
Tag 5: Schneefegen!
Tag 7: Schneefegen!
Tag 9: Schneefegen!
Tag 11: Ausschlafen!

Optionale Aufgabe (Vertiefung): Mit Ausgabe des Wochentages!

Die letzte Aufgabe soll nun noch darum erweitert werden, dass in der Ausgabe auch der Wochentag auftaucht. Tag 1 soll dabei immer der Montag sein.

Hinweis

Ähnlich wie bei b) hilft hier auch der Modulo-Operator %. Mit seiner Hilfe lässt sich eine geeignete Liste ansteuern, welche die Namen der Wochentage enthält.

Lösung

In [43]:
tage_mit_schnee = random.choices([True,False], k=random.randint(1, 30))
wochentage = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"]

for zaehler in range(0,len(tage_mit_schnee),2):
    index_wochentag = zaehler % 7
    if tage_mit_schnee[zaehler]:
        print("Tag " + str(zaehler + 1) + ", " + wochentage[index_wochentag]  + ": Schneefegen!")
    else:
        print("Tag " + str(zaehler + 1) + ", " + wochentage[index_wochentag] + ": Ausschlafen!")
Tag 1, Mo: Ausschlafen!

Programmflusskontrolle C: Schleifen mit while

In den vorherigen Beispielen war die notwendige Anzahl von Iterationen durch die Schleifen vorbestimmt, z.B. durch die Länge des betreffenden Vektors. Denkbar sind jedoch auch Situationen, wo dies nicht der Fall ist.

Beispiel Windkraftanlage

An einer Windkraftanlage befindet sich ein Windmesser, der die Windgeschwindigkeit v_wind misst (wir simulieren diese Messung hier der Einfachheit halber mit dem Zufallsgenerator). Die Anlage soll laufen, solange die Windgeschwindigkeit unter 20 m/s liegt und sich bei einer höheren Geschwindigkeit abschalten.

In [44]:
v = 5  # Anfangswert der Windgeschwindigkeit
v_max  = 20 # Abschaltgeschwindigkeit

while v < v_max:
    print("Wind = %.1f m/s --> Anlage läuft." % v)
    # Windmessung: hier zufällige Änderung der Windgeschwindigkeit
    v = max(0, v + random.uniform(-v/2, (1.2*v_max-v)/2))
print("Wind = %.1f m/s --> ANLAGE GESTOPPT." % v)
Wind = 5.0 m/s --> Anlage läuft.
Wind = 6.8 m/s --> Anlage läuft.
Wind = 14.2 m/s --> Anlage läuft.
Wind = 12.5 m/s --> Anlage läuft.
Wind = 11.6 m/s --> Anlage läuft.
Wind = 15.7 m/s --> Anlage läuft.
Wind = 12.9 m/s --> Anlage läuft.
Wind = 12.1 m/s --> Anlage läuft.
Wind = 13.3 m/s --> Anlage läuft.
Wind = 10.3 m/s --> Anlage läuft.
Wind = 12.5 m/s --> Anlage läuft.
Wind = 17.8 m/s --> Anlage läuft.
Wind = 15.9 m/s --> Anlage läuft.
Wind = 8.6 m/s --> Anlage läuft.
Wind = 13.5 m/s --> Anlage läuft.
Wind = 15.8 m/s --> Anlage läuft.
Wind = 18.3 m/s --> Anlage läuft.
Wind = 12.5 m/s --> Anlage läuft.
Wind = 11.4 m/s --> Anlage läuft.
Wind = 9.5 m/s --> Anlage läuft.
Wind = 13.7 m/s --> Anlage läuft.
Wind = 17.7 m/s --> Anlage läuft.
Wind = 12.5 m/s --> Anlage läuft.
Wind = 13.8 m/s --> Anlage läuft.
Wind = 9.1 m/s --> Anlage läuft.
Wind = 6.4 m/s --> Anlage läuft.
Wind = 10.3 m/s --> Anlage läuft.
Wind = 12.0 m/s --> Anlage läuft.
Wind = 15.8 m/s --> Anlage läuft.
Wind = 9.5 m/s --> Anlage läuft.
Wind = 12.3 m/s --> Anlage läuft.
Wind = 9.1 m/s --> Anlage läuft.
Wind = 15.5 m/s --> Anlage läuft.
Wind = 14.2 m/s --> Anlage läuft.
Wind = 7.4 m/s --> Anlage läuft.
Wind = 5.5 m/s --> Anlage läuft.
Wind = 9.0 m/s --> Anlage läuft.
Wind = 8.4 m/s --> Anlage läuft.
Wind = 4.7 m/s --> Anlage läuft.
Wind = 8.5 m/s --> Anlage läuft.
Wind = 12.9 m/s --> Anlage läuft.
Wind = 15.5 m/s --> Anlage läuft.
Wind = 18.0 m/s --> Anlage läuft.
Wind = 16.1 m/s --> Anlage läuft.
Wind = 12.3 m/s --> Anlage läuft.
Wind = 6.7 m/s --> Anlage läuft.
Wind = 8.8 m/s --> Anlage läuft.
Wind = 6.0 m/s --> Anlage läuft.
Wind = 12.1 m/s --> Anlage läuft.
Wind = 10.1 m/s --> Anlage läuft.
Wind = 12.8 m/s --> Anlage läuft.
Wind = 15.0 m/s --> Anlage läuft.
Wind = 14.3 m/s --> Anlage läuft.
Wind = 13.2 m/s --> Anlage läuft.
Wind = 16.8 m/s --> Anlage läuft.
Wind = 19.7 m/s --> Anlage läuft.
Wind = 17.3 m/s --> Anlage läuft.
Wind = 10.7 m/s --> Anlage läuft.
Wind = 12.8 m/s --> Anlage läuft.
Wind = 10.3 m/s --> Anlage läuft.
Wind = 7.3 m/s --> Anlage läuft.
Wind = 5.8 m/s --> Anlage läuft.
Wind = 7.8 m/s --> Anlage läuft.
Wind = 11.0 m/s --> Anlage läuft.
Wind = 13.1 m/s --> Anlage läuft.
Wind = 9.1 m/s --> Anlage läuft.
Wind = 14.0 m/s --> Anlage läuft.
Wind = 14.4 m/s --> Anlage läuft.
Wind = 18.5 m/s --> Anlage läuft.
Wind = 14.4 m/s --> Anlage läuft.
Wind = 15.0 m/s --> Anlage läuft.
Wind = 12.0 m/s --> Anlage läuft.
Wind = 13.4 m/s --> Anlage läuft.
Wind = 14.9 m/s --> Anlage läuft.
Wind = 8.9 m/s --> Anlage läuft.
Wind = 12.4 m/s --> Anlage läuft.
Wind = 7.7 m/s --> Anlage läuft.
Wind = 7.5 m/s --> Anlage läuft.
Wind = 8.9 m/s --> Anlage läuft.
Wind = 10.7 m/s --> Anlage läuft.
Wind = 11.5 m/s --> Anlage läuft.
Wind = 8.9 m/s --> Anlage läuft.
Wind = 10.3 m/s --> Anlage läuft.
Wind = 13.1 m/s --> Anlage läuft.
Wind = 11.0 m/s --> Anlage läuft.
Wind = 7.5 m/s --> Anlage läuft.
Wind = 8.4 m/s --> Anlage läuft.
Wind = 15.4 m/s --> Anlage läuft.
Wind = 11.5 m/s --> Anlage läuft.
Wind = 9.9 m/s --> Anlage läuft.
Wind = 8.0 m/s --> Anlage läuft.
Wind = 14.9 m/s --> Anlage läuft.
Wind = 10.9 m/s --> Anlage läuft.
Wind = 8.1 m/s --> Anlage läuft.
Wind = 10.3 m/s --> Anlage läuft.
Wind = 10.2 m/s --> Anlage läuft.
Wind = 5.9 m/s --> Anlage läuft.
Wind = 6.2 m/s --> Anlage läuft.
Wind = 8.0 m/s --> Anlage läuft.
Wind = 11.9 m/s --> Anlage läuft.
Wind = 9.2 m/s --> Anlage läuft.
Wind = 14.7 m/s --> Anlage läuft.
Wind = 13.2 m/s --> Anlage läuft.
Wind = 10.3 m/s --> Anlage läuft.
Wind = 12.7 m/s --> Anlage läuft.
Wind = 14.4 m/s --> Anlage läuft.
Wind = 9.1 m/s --> Anlage läuft.
Wind = 13.2 m/s --> Anlage läuft.
Wind = 10.8 m/s --> Anlage läuft.
Wind = 9.6 m/s --> Anlage läuft.
Wind = 8.4 m/s --> Anlage läuft.
Wind = 11.6 m/s --> Anlage läuft.
Wind = 12.8 m/s --> Anlage läuft.
Wind = 14.6 m/s --> Anlage läuft.
Wind = 9.4 m/s --> Anlage läuft.
Wind = 14.4 m/s --> Anlage läuft.
Wind = 16.3 m/s --> Anlage läuft.
Wind = 13.0 m/s --> Anlage läuft.
Wind = 9.6 m/s --> Anlage läuft.
Wind = 9.5 m/s --> Anlage läuft.
Wind = 11.3 m/s --> Anlage läuft.
Wind = 9.2 m/s --> Anlage läuft.
Wind = 12.6 m/s --> Anlage läuft.
Wind = 11.9 m/s --> Anlage läuft.
Wind = 9.6 m/s --> Anlage läuft.
Wind = 12.4 m/s --> Anlage läuft.
Wind = 10.4 m/s --> Anlage läuft.
Wind = 5.4 m/s --> Anlage läuft.
Wind = 7.0 m/s --> Anlage läuft.
Wind = 9.2 m/s --> Anlage läuft.
Wind = 6.7 m/s --> Anlage läuft.
Wind = 12.2 m/s --> Anlage läuft.
Wind = 12.8 m/s --> Anlage läuft.
Wind = 15.4 m/s --> Anlage läuft.
Wind = 18.3 m/s --> Anlage läuft.
Wind = 11.6 m/s --> Anlage läuft.
Wind = 15.7 m/s --> Anlage läuft.
Wind = 9.1 m/s --> Anlage läuft.
Wind = 13.5 m/s --> Anlage läuft.
Wind = 16.4 m/s --> Anlage läuft.
Wind = 19.8 m/s --> Anlage läuft.
Wind = 13.7 m/s --> Anlage läuft.
Wind = 7.0 m/s --> Anlage läuft.
Wind = 7.5 m/s --> Anlage läuft.
Wind = 13.1 m/s --> Anlage läuft.
Wind = 6.9 m/s --> Anlage läuft.
Wind = 9.2 m/s --> Anlage läuft.
Wind = 16.1 m/s --> Anlage läuft.
Wind = 11.8 m/s --> Anlage läuft.
Wind = 17.2 m/s --> Anlage läuft.
Wind = 15.5 m/s --> Anlage läuft.
Wind = 14.0 m/s --> Anlage läuft.
Wind = 16.0 m/s --> Anlage läuft.
Wind = 18.5 m/s --> Anlage läuft.
Wind = 15.6 m/s --> Anlage läuft.
Wind = 12.0 m/s --> Anlage läuft.
Wind = 6.8 m/s --> Anlage läuft.
Wind = 6.9 m/s --> Anlage läuft.
Wind = 7.1 m/s --> Anlage läuft.
Wind = 14.9 m/s --> Anlage läuft.
Wind = 17.1 m/s --> Anlage läuft.
Wind = 13.9 m/s --> Anlage läuft.
Wind = 14.7 m/s --> Anlage läuft.
Wind = 9.5 m/s --> Anlage läuft.
Wind = 8.6 m/s --> Anlage läuft.
Wind = 11.1 m/s --> Anlage läuft.
Wind = 14.6 m/s --> Anlage läuft.
Wind = 12.0 m/s --> Anlage läuft.
Wind = 14.9 m/s --> Anlage läuft.
Wind = 15.7 m/s --> Anlage läuft.
Wind = 12.4 m/s --> Anlage läuft.
Wind = 12.6 m/s --> Anlage läuft.
Wind = 13.0 m/s --> Anlage läuft.
Wind = 10.8 m/s --> Anlage läuft.
Wind = 11.4 m/s --> Anlage läuft.
Wind = 11.1 m/s --> Anlage läuft.
Wind = 9.5 m/s --> Anlage läuft.
Wind = 9.5 m/s --> Anlage läuft.
Wind = 6.7 m/s --> Anlage läuft.
Wind = 8.6 m/s --> Anlage läuft.
Wind = 9.5 m/s --> Anlage läuft.
Wind = 9.1 m/s --> Anlage läuft.
Wind = 10.0 m/s --> Anlage läuft.
Wind = 16.6 m/s --> Anlage läuft.
Wind = 8.9 m/s --> Anlage läuft.
Wind = 16.3 m/s --> Anlage läuft.
Wind = 12.9 m/s --> Anlage läuft.
Wind = 9.7 m/s --> Anlage läuft.
Wind = 12.0 m/s --> Anlage läuft.
Wind = 10.7 m/s --> Anlage läuft.
Wind = 9.9 m/s --> Anlage läuft.
Wind = 15.2 m/s --> Anlage läuft.
Wind = 16.8 m/s --> Anlage läuft.
Wind = 11.0 m/s --> Anlage läuft.
Wind = 7.7 m/s --> Anlage läuft.
Wind = 15.1 m/s --> Anlage läuft.
Wind = 12.5 m/s --> Anlage läuft.
Wind = 16.9 m/s --> Anlage läuft.
Wind = 13.4 m/s --> Anlage läuft.
Wind = 18.5 m/s --> Anlage läuft.
Wind = 10.0 m/s --> Anlage läuft.
Wind = 7.4 m/s --> Anlage läuft.
Wind = 9.2 m/s --> Anlage läuft.
Wind = 8.2 m/s --> Anlage läuft.
Wind = 15.0 m/s --> Anlage läuft.
Wind = 18.0 m/s --> Anlage läuft.
Wind = 18.7 m/s --> Anlage läuft.
Wind = 20.3 m/s --> ANLAGE GESTOPPT.

while macht also so lange weiter, bis das Kriterium (hier v < v_max) nicht mehr erfüllt ist. Die Prüfung erfolgt immer am Anfang, also bevor der Block ausgeführt wird.

Achtung: Fehlerhafte while-Schleifen können schnell zur "Endlosschleife" werden, wenn das Kriterium einfach immer erfüllt wird. Entsprechende Bugs (Fehler) können Programmabläufe erheblich stören.

Aufgabe Windkraftanlage

Die Anlage soll nun nach maximal 10 Zyklen gestoppt werden, um gewartet werden zu können. Ist die Maximalgeschwindigkeit vorher erreicht, wird wie bisher auch angehalten. Der Wert des Zählerstands der Zyklen soll zusätzlich zur Windgeschwindigkeit ausgegeben werden.

Lösung

In [45]:
v = 5 # Anfangswert der Windgeschwindigkeit
v_max  = 20 # Abschaltgeschwindigkeit
zaehler = 0 # zählt die Schleifendurchläufe
zaehler_max = 10 # Maximale Anzahl an Zyklen

while (v < 20) and (zaehler < zaehler_max):
    print("Zyklus %d: Wind = %.1f m/s --> Anlage läuft." % (zaehler, v))
    v = max(0, v + random.uniform(-v/2, (1.5*v_max-v)/2))
    zaehler = zaehler + 1
print("Zyklus %d: Wind = %.1f m/s --> ANLAGE GESTOPPT." % (zaehler, v))
Zyklus 0: Wind = 5.0 m/s --> Anlage läuft.
Zyklus 1: Wind = 3.7 m/s --> Anlage läuft.
Zyklus 2: Wind = 3.5 m/s --> Anlage läuft.
Zyklus 3: Wind = 16.0 m/s --> Anlage läuft.
Zyklus 4: Wind = 21.9 m/s --> ANLAGE GESTOPPT.

Programmflusskontrolle D: Schleifen-Steuerung mit continue und break

Innerhalb von for und while-Schleifen lässt sich mit den Befehlen continue und break der Programmablauf noch flexibler gestalten: continue springt dabei wieder an den Schleifenanfang, während break die Schleife verlässt. Beide Befehle beziehen sich immer nur auf die innerste Schleife. Bei geschachtelten Schleifen werden also die äußeren Schleifen weiter ausgeführt.

In [46]:
# Beispiel: 3 überspringen und bei 5 abbrechen:
for i in range(8):
    if i==3:
        print("Nö.")
        continue
    if i==5:
        print("Schluss jetzt!")
        break
    print(i)
0
1
2
Nö.
4
Schluss jetzt!

Die Windkraftanlage können wir auch mit for und unter Nutzung von break steuern:

In [47]:
v_max  = 20 # Abschaltgeschwindigkeit
zaehler = 0 # zählt die Schleifendurchläufe
zaehler_max = 10 # Maximale Anzahl an Zyklen

for i in range(zaehler_max):
    v = max(0, v + random.uniform(-v/2, (1.4*v_max-v)/2))
    if v < 20:
        print("Zyklus %d: Wind = %.1f m/s --> Anlage läuft." % (i+1, v))
    else:
        print("Zyklus %d: Wind = %.1f m/s --> ANLAGE GESTOPPT." % (i+1, v))
        break        
Zyklus 1: Wind = 20.2 m/s --> ANLAGE GESTOPPT.

Vertiefungen für die Codingwerkstatt

Gedrosselte Windkraft

Bei Geschwindigkeiten von 12 bis 20 soll die Anlage nun außerdem gedrosselt werden. Dies soll durch die Ausgabe ... --> Anlage gedrosselt vermerkt werden.

Lösung

In [48]:
v_max  = 20 # Abschaltgeschwindigkeit
zaehler = 0 # zählt die Schleifendurchläufe
zaehler_max = 10 # Maximale Anzahl an Zyklen

for i in range(zaehler_max):
    v = max(0, v + random.uniform(-v/2, (1.4*v_max-v)/2))
    if v >= 20:
        print("Zyklus %d: Wind = %.1f m/s --> ANLAGE GESTOPPT." % (i+1, v))
        break
    elif v > 12 and v < 20:
        print("Zyklus %d: Wind = %.1f m/s --> ANLAGE GEDROSSELT." % (i+1, v))
    else:
        print("Zyklus %d: Wind = %.1f m/s --> Anlage läuft." % (i+1, v))
Zyklus 1: Wind = 22.1 m/s --> ANLAGE GESTOPPT.

Unvollständiges Alphabet

Fritzchen soll vier mal das Alphabet aufsagen. Er kennt es aber nur bis zum "G", und das "D" vergisst er auch jedes Mal. Das Alphabet holen wir uns wie folgt rein:

In [49]:
import string
In [50]:
Letters = list(string.ascii_lowercase)  #voreingstelltes Alphabet
print(list(string.ascii_lowercase)) 
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']

Lösung

In [51]:
for zaehler in range(0,4):
    print("%d. Mal:" % (zaehler+1))
    for buchstabe in Letters:
        if buchstabe == "d":  #das "d" wird vergessen
            continue          #die Schleife geht zum nächsten Zähler
        print(buchstabe)
        if buchstabe == "g":
            break             # hier wird die Schleife beendet
1. Mal:
a
b
c
e
f
g
2. Mal:
a
b
c
e
f
g
3. Mal:
a
b
c
e
f
g
4. Mal:
a
b
c
e
f
g

Für noch nicht Ausgelastete nun der Klassiker: Primzahlen suchen

Finde alle Primzahlen von 1 bis 100! Nutze dazu die Modulo-Funktion. Liefere am Ende einen Vektor von Wahrheitswerten ist_primzahl[1:100], in dem die Einträge für Primzahlen TRUE sind.

Hinweis

Der Floor-Operator // könnte hier hilfreich sein. Dieser gibt nur den ganzzahligen Teiler aus und ignoriert den Rest.