{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "Python Einführungskurs für das Physikalische Anfängerpraktikum der Universität Heidelberg | [Startseite](index.ipynb)\n", "\n", "---" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 102 - Control Flow" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- [`if`-Abfragen](#if-Abfragen)\n", "- [Aufgabe 1 - Raumtemperatur](#Aufgabe-1---Raumtemperatur)\n", "- [`for`-Schleifen](#for-Schleifen)\n", "- [Aufgabe 2 - Primzahlen](#Aufgabe-2---Primzahlen)\n", "- [`while`-Schleifen](#while-Schleifen)\n", "- [Aufgabe 3 - Fibonacci](#Aufgabe-3---Fibonacci)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Wir können Variablen nun Werte verschiedener Typen zuweisen:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a = 1\n", "b = 3.14\n", "c = 'hello'\n", "d = [a, b, c]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## `if`-Abfragen\n", "\n", "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:\n", "```python\n", "if condition:\n", " # do something\n", "elif condition:\n", " # do something else\n", "else:\n", " # do yet something else\n", "```\n", "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**.\n", "\n", "> **Hinweis:** In Python werden Codeblöcke durch Doppelpunkte und Einrückungen begrenzt. Per Konvention werden dazu jeweils vier Leerzeichen pro Einrückungslevel verwendet." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Verändere bspw. im folgenden Code den Wert von `a` und schaue, wie sich der Output verändert." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a = 1\n", "if a < 5:\n", " print(\"a ist zu klein, setze auf 5\")\n", " a = 5\n", "else:\n", " print(\"a ist groß genug.\")\n", "print(\"a ist nun {}.\".format(a))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Vergleichs-Operatoren produzieren Booleans\n", "\n", "Die Bedingung der `if`-Abfrage kann alles sein, was einen `bool`-Wert zurückgibt.\n", "\n", "Werte von Datentypen, die Vergleiche unterstützen, können mit Vergleichs-Operatoren zu einem Boolean kombiniert werden:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "1 == 3 # \"gleich\"" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "1 != 3 # \"ungleich\"" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "1 > 3 # \"größer\"" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "3 <= 3.4 # \"kleiner oder gleich\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "> Die einfachsten Bedingungen sind die expliziten `bool`-Werte `True` und `False`. Beachte, dass `True` und `False` in Python mit großem Anfangsbuchstaben geschrieben werden." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Logische Operatoren kombinieren Booleans\n", "\n", "Booleans können mit den logischen Operatoren `and`, `or` und `not` kombiniert werden:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "True and False" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "True or False" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "not True" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "(False and (True or False)) or (False and True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Aufgabe 1 - Raumtemperatur\n", "\n", "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.\n", "\n", "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.\n", "\n", "Probiere dein erstes kleines Programm aus, indem du den Wert von `T` veränderst." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "nbgrader": { "grade": false, "grade_id": "102-1-sol", "locked": false, "schema_version": 1, "solution": true } }, "outputs": [], "source": [ "T = 20\n", "T_Raum = 21\n", "heating = False\n", "### BEGIN SOLUTION\n", "if T == T_Raum:\n", " print(\"Temperatur bei Raumtemperatur.\")\n", "elif T < T_Raum:\n", " print(\"zu kalt!\")\n", "elif T > T_Raum:\n", " print(\"zu warm!\")\n", "heating = T < T_Raum\n", "if heating:\n", " print(\"Es wird geheizt.\")\n", "else:\n", " print(\"Heizung ist aus.\")\n", "### END SOLUTION" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "nbgrader": { "grade": true, "grade_id": "102-1-test", "locked": true, "points": 2, "schema_version": 1, "solution": false } }, "outputs": [], "source": [ "from nose.tools import assert_equal\n", "assert_equal(heating, T < T_Raum, \"Der Wert von `heating` passt nicht. Setze den Wert nur dann auf `True`, wenn `T < T_R` ist.\")\n", "print(\"👏 Easy.\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Weitere Bool'sche Operatoren\n", "\n", "Python stellt noch einige weitere nützliche Operatoren zur Verfügung." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- Der `in` Operator prüft, ob ein Wert in einer Reihe enthalten ist:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "3 in [ 1, 3, 5 ]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- Der `is` Operator prüft, ob zwei Objekte _identisch_ sind, also ein und dasselbe Objekt sind." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "s = \"Hello World\"\n", "t = \"Hello World\"\n", "s == t, s is t" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "1000 == 10**3, 1000 is 10**3" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "> 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.\n", ">\n", "> 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:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a = None\n", "if a is None:\n", " print(\"a hat keinen Wert!\")\n", "else:\n", " print(\"a ist {}.\".format(a))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## `for`-Schleifen\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Mit Schleifen kann ein Codeblock mehrmals ausgeführt werden. Die meistverwendete Schleife ist die `for`-Schleife mit folgender Syntax:\n", "\n", "```python\n", "for value in iterable:\n", " # do things\n", "```\n", "\n", "`iterable` kann dabei eine beliebige _Reihe_ sein, also bspw. eine Liste, ein Tupel oder auch ein String:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "for x in [3, 1.2, 'a']:\n", " print(x)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "for letter in 'hello':\n", " print(letter)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Einen Codeblock `n`-mal ausführen\n", "\n", "Manchmal soll ein Codeblock eine bestimmte Zahl von Iterationen ausgeführt werden. Dazu können wir die `range` Funktion verwenden:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "for i in range(5):\n", " print(i)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#range?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Wir können die Funktion also auch mit den Argumenten `start`, `stop` und (optional) `step` aufrufen:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "for i in range(2, 10, 2):\n", " print(i)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Eine Schleife abbrechen oder Schritte überspringen" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- Mit dem Befehl `break` kann eine Schleife abgebrochen werden:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "for i in range(100):\n", " if i > 3:\n", " break\n", " print(i)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- Mit dem Befehl `continue` wird lediglich der aktuelle Schritt der Schleife abgebrochen:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "for i in range(3):\n", " if i == 1:\n", " continue\n", " print(i)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Listen mit `for`-Schleifen erstellen\n", "\n", "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:\n", "\n", "```python\n", "new_elements = [operation(element) for element in iterable]\n", "```\n", "\n", "Hier wird bspw. die Operation $x^2$ auf alle $x \\in [0,10]$ angewendet:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "[x**2 for x in range(11)]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Aufgabe 2 - Primzahlen\n", "\n", "Schreibe ein Programm, das alle Primzahlen kleiner `50` bestimmt. Füge sie der Liste `primes` hinzu.\n", "\n", "**Hinweis:** Der `%`-Operator gibt den Rest der Division zweier Integer zurück.\n", "\n", "**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.\n", "\n", "**Erinnerung:** Mit der `append` Methode können wir Elemente einer Liste hinzufügen." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "nbgrader": { "grade": false, "grade_id": "102-2-sol", "locked": false, "schema_version": 1, "solution": true } }, "outputs": [], "source": [ "primes = []\n", "### BEGIN SOLUTION\n", "for n in range(50):\n", " is_prime = True\n", " for m in range(2, n):\n", " if n % m == 0:\n", " is_prime = False\n", " break\n", " if is_prime:\n", " primes.append(n)\n", "### END SOLUTION\n", "primes" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "nbgrader": { "grade": true, "grade_id": "102-2-test", "locked": true, "points": 2, "schema_version": 1, "solution": false } }, "outputs": [], "source": [ "from nose.tools import assert_equal\n", "trimmed_primes = primes\n", "for x in [ 0, 1 ]:\n", " try:\n", " trimmed_primes.remove(x)\n", " except ValueError:\n", " pass\n", "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\")\n", "print(\"Sehr gut! 🎉🎉🎉\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## `while`-Schleifen\n", "\n", "Eine `while`-Schleife führt einen Codeblock so oft aus, bis eine Bedingung `False` ergibt und ist durch folgende Syntax definiert:\n", "\n", "```python\n", "while condition:\n", " # do something\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a = 1\n", "while a < 10:\n", " print(\"a ist kleiner als 10 ({}), multipliziere mit 1.5.\".format(a))\n", " a = a * 1.5\n", "print(\"Schleife beendet, a ist nun {}.\".format(a))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Aufgabe 3 - Fibonacci\n", "\n", "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.\n", "\n", "**Erinnerung:** Auf das letzte Element einer Reihe können wir mit dem Subskript `l[-1]` zugreifen. Das vorletzte Element ist dann entsprechend `l[-2]`." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "nbgrader": { "grade": false, "grade_id": "102-3-sol", "locked": false, "schema_version": 1, "solution": true } }, "outputs": [], "source": [ "fib_numbers = [ 0, 1 ]\n", "### BEGIN SOLUTION\n", "while fib_numbers[-1] + fib_numbers[-2] < 100:\n", " fib_numbers.append(fib_numbers[-1] + fib_numbers[-2])\n", "### END SOLUTION\n", "fib_numbers" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "nbgrader": { "grade": true, "grade_id": "102-3-test", "locked": true, "points": 2, "schema_version": 1, "solution": false } }, "outputs": [], "source": [ "from nose.tools import assert_equal\n", "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.\")\n", "print(\"👌 Richtig!\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "\n", "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.\n", "\n", "[Startseite](index.ipynb) | [**>> 103 - Funktionen und Module**](103%20-%20Funktionen%20und%20Module.ipynb)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.0" } }, "nbformat": 4, "nbformat_minor": 1 }