#!/usr/bin/env python # coding: utf-8 # Python Einführungskurs für das Physikalische Anfängerpraktikum der Universität Heidelberg | [Startseite](index.ipynb) # # --- # # 102 - Control Flow # - [`if`-Abfragen](#if-Abfragen) # - [Aufgabe 1 - Raumtemperatur](#Aufgabe-1---Raumtemperatur) # - [`for`-Schleifen](#for-Schleifen) # - [Aufgabe 2 - Primzahlen](#Aufgabe-2---Primzahlen) # - [`while`-Schleifen](#while-Schleifen) # - [Aufgabe 3 - Fibonacci](#Aufgabe-3---Fibonacci) # Wir können Variablen nun Werte verschiedener Typen zuweisen: # In[ ]: a = 1 b = 3.14 c = 'hello' d = [a, b, c] # Doch um ein sinnvolles Programm zu schreiben benötigen wir sog. _Control Flow_ Anweisungen, die steuern, wie sich das Programm je nach Situation zu verhalten hat. Dazu gehören vor allem `if`-Abfragen und `for`- und `while`-Schleifen. # ## `if`-Abfragen # # Die einfachste Form von _control flow_ ist die `if`-Abfrage. Ein Codeblock wird nur dann ausgeführt, wenn eine Bedingung den `bool`-Wert `True` ergibt. Ein optionaler `else`-Codeblock kann ausgeführt werden, wenn die Bedingung _nicht_ `True` ergibt. Die Syntax für `if`-Abfragen lautet wie folgt: # ```python # if condition: # # do something # elif condition: # # do something else # else: # # do yet something else # ``` # Beachtet, dass die Codeblöcke nicht durch Steuerzeichen begrenzt werden. Stattdessen endet die Bedingung lediglich mit einem Doppelpunkt (`:`) und der zugehörige der Codeblock ist **eingerückt**. # # > **Hinweis:** In Python werden Codeblöcke durch Doppelpunkte und Einrückungen begrenzt. Per Konvention werden dazu jeweils vier Leerzeichen pro Einrückungslevel verwendet. # Verändere bspw. im folgenden Code den Wert von `a` und schaue, wie sich der Output verändert. # In[ ]: a = 1 if a < 5: print("a ist zu klein, setze auf 5") a = 5 else: print("a ist groß genug.") print("a ist nun {}.".format(a)) # Der erste Aufruf der `print`-Funktion und die Änderung des Werts von `a` wird nur ausgeführt, wenn der Wert von `a` kleiner als `5` ist. Ansonsten wird der `else`-Block ausgeführt. Der letzte Aufruf der `print`-Funktion wird jedoch immer ausgeführt. # ### Vergleichs-Operatoren produzieren Booleans # # Die Bedingung der `if`-Abfrage kann alles sein, was einen `bool`-Wert zurückgibt. # # Werte von Datentypen, die Vergleiche unterstützen, können mit Vergleichs-Operatoren zu einem Boolean kombiniert werden: # In[ ]: 1 == 3 # "gleich" # In[ ]: 1 != 3 # "ungleich" # In[ ]: 1 > 3 # "größer" # In[ ]: 3 <= 3.4 # "kleiner oder gleich" # > Die einfachsten Bedingungen sind die expliziten `bool`-Werte `True` und `False`. Beachte, dass `True` und `False` in Python mit großem Anfangsbuchstaben geschrieben werden. # ### Logische Operatoren kombinieren Booleans # # Booleans können mit den logischen Operatoren `and`, `or` und `not` kombiniert werden: # In[ ]: True and False # In[ ]: True or False # In[ ]: not True # In[ ]: (False and (True or False)) or (False and True) # ## Aufgabe 1 - Raumtemperatur # # a) Schreibe eine `if`-Abfrage, die die Temperatur `T` mit der Raumtemperatur `T_Raum` vergleicht und mit `print` ausgibt, ob die Temperatur zu warm, zu kalt oder genau bei Raumtemperatur ist. # # b) Setze den Boolean-Wert der Variable `heating` auf `True`, wenn die Temperatur unter der Raumtemperatur liegt, und andernfalls auf `False`. Du kannst dies entweder explizit in die `if`-Abfrage integrieren oder separat durch einen Boolean-Ausdruck setzen. Gib je nach dem Wert von `heating` mit `print` aus, ob geheizt wird oder nicht. # # Probiere dein erstes kleines Programm aus, indem du den Wert von `T` veränderst. # In[ ]: T = 20 T_Raum = 21 heating = False ### BEGIN SOLUTION if T == T_Raum: print("Temperatur bei Raumtemperatur.") elif T < T_Raum: print("zu kalt!") elif T > T_Raum: print("zu warm!") heating = T < T_Raum if heating: print("Es wird geheizt.") else: print("Heizung ist aus.") ### END SOLUTION # In[ ]: from nose.tools import assert_equal assert_equal(heating, T < T_Raum, "Der Wert von `heating` passt nicht. Setze den Wert nur dann auf `True`, wenn `T < T_R` ist.") print("👏 Easy.") # ### Weitere Bool'sche Operatoren # # Python stellt noch einige weitere nützliche Operatoren zur Verfügung. # - Der `in` Operator prüft, ob ein Wert in einer Reihe enthalten ist: # In[ ]: 3 in [ 1, 3, 5 ] # - Der `is` Operator prüft, ob zwei Objekte _identisch_ sind, also ein und dasselbe Objekt sind. # In[ ]: s = "Hello World" t = "Hello World" s == t, s is t # In[ ]: 1000 == 10**3, 1000 is 10**3 # > Meistens sind wir nur an der _Gleichheit_ von Werten interessiert und verwenden den Gleichheits-Operator (`==`). Die _Identität_ von Objekten wird erst in der _Objektorientierten Programmierung_ relevant wenn wir mit _Reference_-Typen arbeiten, statt wie bisher mit _Value_-Typen. # > # > Ein häufiger Anwendungsfall für den Identitäts-Operator `is` ist jedoch der Vergleich mit `None`. Das Symbol `None` stellt das Nicht-Vorhandensein eines Wertes in Python dar: # In[ ]: a = None if a is None: print("a hat keinen Wert!") else: print("a ist {}.".format(a)) # ## `for`-Schleifen # # Mit Schleifen kann ein Codeblock mehrmals ausgeführt werden. Die meistverwendete Schleife ist die `for`-Schleife mit folgender Syntax: # # ```python # for value in iterable: # # do things # ``` # # `iterable` kann dabei eine beliebige _Reihe_ sein, also bspw. eine Liste, ein Tupel oder auch ein String: # In[ ]: for x in [3, 1.2, 'a']: print(x) # In[ ]: for letter in 'hello': print(letter) # ### Einen Codeblock `n`-mal ausführen # # Manchmal soll ein Codeblock eine bestimmte Zahl von Iterationen ausgeführt werden. Dazu können wir die `range` Funktion verwenden: # In[ ]: for i in range(5): print(i) # Du kannst nachschauen, wie die `range` Funktion definiert ist und welche Optionen sie bietet, indem du die `?`-Dokumentation aufrufst. Entferne das `#`-Zeichen und führe die Zelle aus: # In[ ]: #range? # Wir können die Funktion also auch mit den Argumenten `start`, `stop` und (optional) `step` aufrufen: # In[ ]: for i in range(2, 10, 2): print(i) # ### Eine Schleife abbrechen oder Schritte überspringen # - Mit dem Befehl `break` kann eine Schleife abgebrochen werden: # In[ ]: for i in range(100): if i > 3: break print(i) # - Mit dem Befehl `continue` wird lediglich der aktuelle Schritt der Schleife abgebrochen: # In[ ]: for i in range(3): if i == 1: continue print(i) # ### Listen mit `for`-Schleifen erstellen # # Ein sehr praktisches Konzept um in Python mit Listen zu arbeiten nennt sich _list comprehension_. Mit folgender Syntax wird eine Operation auf jedes Element der gegebenen Reihe angewendet. Zurückgegeben wird dann eine Liste mit den so berechneten Elementen: # # ```python # new_elements = [operation(element) for element in iterable] # ``` # # Hier wird bspw. die Operation $x^2$ auf alle $x \in [0,10]$ angewendet: # In[ ]: [x**2 for x in range(11)] # ## Aufgabe 2 - Primzahlen # # Schreibe ein Programm, das alle Primzahlen kleiner `50` bestimmt. Füge sie der Liste `primes` hinzu. # # **Hinweis:** Der `%`-Operator gibt den Rest der Division zweier Integer zurück. # # **Möglicher Ansatz:** Versuch's mal mit einer Boolean-Variable `is_prime` für jede der Zahlen bis `50`, die zunächst `True` ist und dann in einer zweiten `for`-Schleife ggfs. auf `False` gesetzt wird. # # **Erinnerung:** Mit der `append` Methode können wir Elemente einer Liste hinzufügen. # In[ ]: primes = [] ### BEGIN SOLUTION for n in range(50): is_prime = True for m in range(2, n): if n % m == 0: is_prime = False break if is_prime: primes.append(n) ### END SOLUTION primes # In[ ]: from nose.tools import assert_equal trimmed_primes = primes for x in [ 0, 1 ]: try: trimmed_primes.remove(x) except ValueError: pass assert_equal([2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47], trimmed_primes, "Die Liste von Primzahlen sollte bei 0, 1 oder 2 beginnen und die Primzahlen bis inkl. 47 enthalten") print("Sehr gut! 🎉🎉🎉") # ## `while`-Schleifen # # Eine `while`-Schleife führt einen Codeblock so oft aus, bis eine Bedingung `False` ergibt und ist durch folgende Syntax definiert: # # ```python # while condition: # # do something # ``` # In[ ]: a = 1 while a < 10: print("a ist kleiner als 10 ({}), multipliziere mit 1.5.".format(a)) a = a * 1.5 print("Schleife beendet, a ist nun {}.".format(a)) # ## Aufgabe 3 - Fibonacci # # Verwende eine `while`-Schleife um die Zahlen der Fibonacci-Reihe bis 100 der Liste `fib_numbers` hinzuzufügen. Die ersten zwei Zahlen sind `0` und `1` und jede weitere Zahl ist die Summe der beiden vorherigen. # # **Erinnerung:** Auf das letzte Element einer Reihe können wir mit dem Subskript `l[-1]` zugreifen. Das vorletzte Element ist dann entsprechend `l[-2]`. # In[ ]: fib_numbers = [ 0, 1 ] ### BEGIN SOLUTION while fib_numbers[-1] + fib_numbers[-2] < 100: fib_numbers.append(fib_numbers[-1] + fib_numbers[-2]) ### END SOLUTION fib_numbers # In[ ]: from nose.tools import assert_equal assert_equal([0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89], fib_numbers, "Die Liste sollte mit [ 0, 1, 1, 2, ...] beginnen und die Fibonacci-Zahlen bis einschließlich 89 enthalten.") print("👌 Richtig!") # --- # # Du kannst jetzt Programme in Python schreiben, die dir etwas ausrechnen! Lerne in der nächsten Lektion, wie du Code als "Bausteine" deines Programms in _Funktionen_ verpackst. Für viele Probleme gibt es schon Funktionen und du musst sie nur aus _Modulen_ laden. # # [Startseite](index.ipynb) | [**>> 103 - Funktionen und Module**](103%20-%20Funktionen%20und%20Module.ipynb)