"Da das `turtle`-Modul in Jupyter-Notebooks eventuell nicht so gut funktioniert, kann es von Vorteil sein, `turtle` über die Kommandozeile aufzurufen. Dies ist prinzipell auf allen Betriebssystemen möglich, aber auf Linux und MacOS deutlich einfacher als auf Windows.\n",
"Da das `turtle`-Modul in Jupyter-Notebooks eventuell nicht so gut funktioniert, kann es von Vorteil sein, `turtle` über die Kommandozeile aufzurufen. Dies ist prinzipell auf allen Betriebssystemen möglich, aber auf Linux und MacOS deutlich einfacher als auf Windows.\n",
"\n",
"\n",
"Falls Sie Linux nutzen, sollte Python bereits installiert sein. Um das gewünschte Programm zu öffnen tuen Sie folgendes: \n",
"Falls Sie Linux nutzen, sollte Python bereits installiert sein. Um das gewünschte Programm zu öffnen tun Sie folgendes: \n",
"1. Speichern Sie das Programm, das sie aufrufen möchten als PythonProgramm (.py)\n",
"1. Speichern Sie das Programm, das sie aufrufen möchten als Python-Programm mit der Dateiendung `.py`.\n",
"2. Öffnen Sie die Kommandozeile\n",
"2. Öffnen Sie die Kommandozeile.\n",
"3. Gehen Sie entweder in das Verzeichnis, in dem das Programm gespeichert ist, dafür geben Sie `cd /pfad/zum/verzeichnis` ein. \n",
"3. Gehen Sie in das Verzeichnis, in dem das Programm gespeichert ist. Geben Sie dafür `cd /pfad/zum/verzeichnis` ein. \n",
"4. Geben Sie auf der Kommandozeile `python programm.py` ein\n",
"4. Geben Sie auf der Kommandozeile `python programm.py` ein\n",
"5. Alternativ können Sie auch `python /pfad/zum/verzeichnis/programm.py` eingeben. \n",
"5. Alternativ können Sie auch direkt `python /pfad/zum/verzeichnis/programm.py` eingeben. \n",
"\n",
"\n",
"Falls Sie MacOS verwenden, gehen Sie folgendermaßen vor:\n",
"Falls Sie MacOS verwenden, gehen Sie folgendermaßen vor:\n",
"1. Speichern Sie das Programm, dass Sie aufrufen möchten als PythonProgramm (.py)\n",
"1. Speichern Sie das Programm, dass Sie aufrufen möchten als Python-Programm mit der Dateiendug `.py`.\n",
"2. Öffnen Sie das Terminal\n",
"2. Öffnen Sie das Terminal\n",
"3. Gehen Sie in das Verzeichnis, in welchem das Programm gespeichert ist, indem sie `cd pfad/zum/verzeichnis`eingeben\n",
"3. Gehen Sie in das Verzeichnis, in welchem das Programm gespeichert ist, indem sie `cd /pfad/zum/verzeichnis`eingeben\n",
"4. Geben Sie im Termial`python programm.py` ein.\n",
"4. Geben Sie im Termial`python programm.py` ein.\n",
"\n",
"\n",
"Falls Sie Windows verwenden, brauchen Sie beim ersten Aufruf etwas länger und müssen zusätzliche Schritte vornehmen, bei weiterer Verwendung springen Sie direkt zu Punkt 2 der Anleitung:\n",
"Falls Sie Windows verwenden, brauchen Sie beim ersten Aufruf etwas länger und müssen zusätzliche Schritte vornehmen, bei weiterer Verwendung springen Sie direkt zu Punkt 2 der Anleitung:\n",
"1. Fügen Sie Python zur PATH-Umgebung hinzu: \n",
"1. Fügen Sie Python zur PATH-Umgebung hinzu: \n",
" 1.1. Finden Sie heraus wo Anaconda und Python gespeichert sind. (Dafür geben sie im Anaconda Prompt `where anaconda`und `where python` ein) \n",
" 1.1. Finden Sie heraus wo Anaconda und Python gespeichert sind. (Dafür geben sie im Anaconda Prompt `where anaconda`und `where python` ein.) \n",
" 1.2. Öffnen Sie den Explorer und öffnen Sie das Rechtsklick-Menü von `Dieser PC` \n",
" 1.2. Öffnen Sie den Explorer und öffnen Sie das Rechtsklick-Menü von `Dieser PC` \n",
" 1.3. Wählen Sie Eigenschaften \n",
" 1.3. Wählen Sie Eigenschaften \n",
" 1.4. Wählen Sie Erweiterte Systemeinstellungen \n",
" 1.4. Wählen Sie Erweiterte Systemeinstellungen \n",
" 1.5. Wählen Sie Umgebungsvariablen \n",
" 1.5. Wählen Sie Umgebungsvariablen \n",
" 1.6. Klicken Sie `Path`im unteren fenster an und dann auf `bearbeiten` \n",
" 1.6. Klicken Sie `Path`im unteren Fenster an und dann auf `bearbeiten` \n",
" 1.7. Klicken Sie auf `neu`und fügen Sie den Pfad für `Anaconda` hinzu, aber lassen Sie `anaconda.exe` weg \n",
" 1.7. Klicken Sie auf `neu`und fügen Sie den Pfad für `Anaconda` hinzu, aber lassen Sie `anaconda.exe` weg \n",
" 1.8. Wiederholen Sie dasselbe analog für den `Python`Pfad, dabei lassen Sie `python.exe` weg. \n",
" 1.8. Wiederholen Sie dasselbe analog für den `Python`-Pfad, dabei lassen Sie `python.exe` weg. \n",
" 1.9. Klicken Sie 2 mal okay und schließen Sie die Systemsteuerung \n",
" 1.9. Klicken Sie zwei mal okay und schließen Sie die Systemsteuerung \n",
" 1.10. Öffnen Sie die Kommandozeile (`cmd` in der Suchleiste eingeben und `enter` drücken) und geben sie `python` oder `python.exe` ein. Wenn Sie Erfolg hatten, öffnet sich Python und Sie könnten in der Kommandozeile programmieren. \n",
" 1.10. Öffnen Sie die Kommandozeile (`cmd` in der Suchleiste eingeben und `enter` drücken) und geben sie `python` oder `python.exe` ein. Wenn Sie Erfolg hatten, öffnet sich Python und Sie können in der Kommandozeile programmieren. \n",
" 1.11. Verlassen Sie `python` indem sie `exit()` eingeben. \n",
" 1.11. Verlassen Sie `python` indem sie `exit()` eingeben. \n",
"2. Speichern Sie das Programm, das sie aufrufen möchten als PythonProgramm (.py)\n",
"2. Speichern Sie das Programm, das sie aufrufen möchten als Python-Programm mit der Dateiendung `.py`.\n",
"3. Geben Sie in der Kommandozeile `python.exe` und den Pfad zu Ihrem Programm ein (also `C:\\Users\\IhrName\\Documents\\nested\\programm.py`)"
"3. Geben Sie in der Kommandozeile `python.exe` und den Pfad zu Ihrem Programm ein (also `C:\\Users\\IhrName\\Documents\\nested\\programm.py`)"
]
]
},
},
...
@@ -105,9 +105,9 @@
...
@@ -105,9 +105,9 @@
"cell_type": "markdown",
"cell_type": "markdown",
"metadata": {},
"metadata": {},
"source": [
"source": [
"Es sollte sich ein Fenster öffnen, in dem ein kleiner Pfeil zu sehen ist -- dieser repräsentiert die Schildkröte (\"turtle\"). Schließen Sie das Fenster.\n",
"Es sollte sich ein Fenster öffnen, in dem ein kleiner Pfeil zu sehen ist -- dieser repräsentiert die Schildkröte (\"turtle\"). Schließen Sie das Fenster. (Danach erscheint ggf. eine Fehlermeldung -- nicht erschrecken, diese ist im Allgemeinen harmlos.) \n",
"\n",
"\n",
"*(Hinweis: In Jupyter gibt es manchmal Probleme mit dem `turtle`-Modul. Dann hilft es, das Turtle-Fenster zu schließen und den Code nochmal auszuführen oder im Kernel-Menü den Punkt \"Restart & Clear Output\" aufzurufen. Wenn es gar nicht klappt, dann nutzen Sie für die Turtle-Programmierung bitte nicht Jupyter-Notebooks, sondern Python-Dateien und führen diese direkt mit Python aus. \n",
"*(Hinweis: In Jupyter gibt es manchmal Probleme mit dem `turtle`-Modul. **Wichtig ist, dass Sie stets das Turtle-Fenster schließen.** Manchmal hilft es, den Code nochmal auszuführen oder im Kernel-Menü den Punkt \"Restart & Clear Output\" aufzurufen. Wenn es gar nicht klappt, dann nutzen Sie für die Turtle-Programmierung bitte nicht Jupyter-Notebooks, sondern Python-Dateien und führen diese direkt mit Python aus. \n",
"Manchmal vergisst Jupyter Notebooks auch, dass bereits eine Schildkröte existiert, in diesem Fall initialisieren Sie diese bitte einfach am Anfang des gewünschten Code-Blocks)*\n",
"Manchmal vergisst Jupyter Notebooks auch, dass bereits eine Schildkröte existiert, in diesem Fall initialisieren Sie diese bitte einfach am Anfang des gewünschten Code-Blocks)*\n",
"\n",
"\n",
"Probieren Sie nun folgendes (am besten in einem eigenen Jupyter-Notebook, einer eigenen Python-Datei, oder im folgenden Block, den Sie dann schrittweise ergänzen):"
"Probieren Sie nun folgendes (am besten in einem eigenen Jupyter-Notebook, einer eigenen Python-Datei, oder im folgenden Block, den Sie dann schrittweise ergänzen):"
...
@@ -138,7 +138,7 @@
...
@@ -138,7 +138,7 @@
"cell_type": "markdown",
"cell_type": "markdown",
"metadata": {},
"metadata": {},
"source": [
"source": [
"Das `turtle`-Modul (mit kleinem `t`) stellt eine Funktion `Turtle` (mit großem `T`) bereit, die ein Turtle-Objekt erzeugt - dieses weisen wir einer Variable mit dem Namen `bob` zu. Wenn wir `bob` mit `print` ausgeben, erhalten wir eine Ausgabe ähnlich\n",
"Das `turtle`-Modul (mit kleinem `t`) stellt eine Funktion `Turtle` (mit großem `T`) bereit, die ein Turtle-Objekt erzeugt -- dieses weisen wir einer Variable mit dem Namen `bob` zu. Wenn wir `bob` mit `print` ausgeben, erhalten wir eine Ausgabe ähnlich\n",
"\n",
"\n",
"```\n",
"```\n",
"<turtle.Turtle object at 0xb7bfbf4c>\n",
"<turtle.Turtle object at 0xb7bfbf4c>\n",
...
@@ -247,7 +247,10 @@
...
@@ -247,7 +247,10 @@
"\n",
"\n",
"for i in range(4):\n",
"for i in range(4):\n",
" bob.fd(100)\n",
" bob.fd(100)\n",
" bob.lt(90)"
" bob.lt(90)\n",
"\n",
"turtle.mainloop() \n",
"turtle.bye()"
]
]
},
},
{
{
...
@@ -823,7 +826,7 @@
...
@@ -823,7 +826,7 @@
"import turtle\n",
"import turtle\n",
"bob=turtle.Turtle()\n",
"bob=turtle.Turtle()\n",
"\n",
"\n",
"# Damit diese Lösung funktioniert müssen def arc und def polyline bekannt sein.\n",
"# Damit diese Lösung funktioniert müssen die Funktionen arc und polyline schon definiert worden sein.\n",
"\n",
"\n",
"def blatt(t, r, angle):\n",
"def blatt(t, r, angle):\n",
" for i in range (2):\n",
" for i in range (2):\n",
...
@@ -836,7 +839,10 @@
...
@@ -836,7 +839,10 @@
" blatt (t,r,angle)\n",
" blatt (t,r,angle)\n",
" t.lt(360/n)\n",
" t.lt(360/n)\n",
"\n",
"\n",
"blume(bob,60.0,60.0,5)"
"blume(bob,60.0,60.0,5)\n",
"\n",
"turtle.mainloop() \n",
"turtle.bye()"
]
]
},
},
{
{
...
@@ -889,6 +895,8 @@
...
@@ -889,6 +895,8 @@
"import math\n",
"import math\n",
"import turtle\n",
"import turtle\n",
"\n",
"\n",
"# Arbeiten Sie diese Lösung durch und kommentieren Sie die einzelnen Schritte\n",
"\n",
"def stück (t,r, angle):\n",
"def stück (t,r, angle):\n",
" c=2*r*(math.sin(angle*math.pi/180))\n",
" c=2*r*(math.sin(angle*math.pi/180))\n",
" t.rt(angle)\n",
" t.rt(angle)\n",
...
@@ -900,8 +908,6 @@
...
@@ -900,8 +908,6 @@
" t.lt(180-angle)\n",
" t.lt(180-angle)\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"def kuchen (t, n, r):\n",
"def kuchen (t, n, r):\n",
" angle=360/n\n",
" angle=360/n\n",
" for i in range (n):\n",
" for i in range (n):\n",
...
@@ -909,14 +915,13 @@
...
@@ -909,14 +915,13 @@
" t.lt(angle)\n",
" t.lt(angle)\n",
" turtle.mainloop()\n",
" turtle.mainloop()\n",
" turtle.bye()\n",
" turtle.bye()\n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
"bob=turtle.Turtle() \n",
"bob=turtle.Turtle() \n",
"kuchen(bob,4,40,40)"
"kuchen(bob, 5, 100)\n",
"\n",
"turtle.mainloop() \n",
"turtle.bye()"
]
]
},
},
{
{
...
...
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
# Seminar Problemorientierte Programmierung
# Seminar Problemorientierte Programmierung
## 4: Fallstudie: Schnittstellenentwurf
## 4: Fallstudie: Schnittstellenentwurf
[Chapter 4: Case Study: interface design](http://greenteapress.com/thinkpython/html/thinkpython005.html)
[Chapter 4: Case Study: interface design](http://greenteapress.com/thinkpython/html/thinkpython005.html)
In diesem Kapitel lernen wir, anhand einer Fallstudie, wie wir Funktionen entwerfen können, die gut zusammenarbeiten.
In diesem Kapitel lernen wir, anhand einer Fallstudie, wie wir Funktionen entwerfen können, die gut zusammenarbeiten.
Wir lernen außerdem das `turtle`-Modul kennen, mit dessen Hilfe wir Graphiken erzeugen können.
Wir lernen außerdem das `turtle`-Modul kennen, mit dessen Hilfe wir Graphiken erzeugen können.
### Ihre Lernziele
### Ihre Lernziele
Beschreiben Sie in 2-3 Stichpunkten kurz was Sie im Seminar heute lernen wollen. Klicken Sie dazu doppelt auf diesen Text und bearbeiten Sie dann den Text:
Beschreiben Sie in 2-3 Stichpunkten kurz was Sie im Seminar heute lernen wollen. Klicken Sie dazu doppelt auf diesen Text und bearbeiten Sie dann den Text:
-
-
-
-
-
-
### Exkurs: Was mir an Python gefällt
### Exkurs: Was mir an Python gefällt
Man kann schnell und einfach ein Programm aufschreiben und testen. Man muss es weder kompilieren, noch viel "unnötige" Syntax kennen:
Man kann schnell und einfach ein Programm aufschreiben und testen. Man muss es weder kompilieren, noch viel "unnötige" Syntax kennen:
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
def factorial(n):
def factorial(n):
if n < 2:
if n < 2:
return 1
return 1
else:
else:
return n * factorial(n - 1)
return n * factorial(n - 1)
print(factorial(5))
print(factorial(5))
```
```
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
### 4.0 Python für das `turtle`-Modul
### 4.0 Python für das `turtle`-Modul
Da das `turtle`-Modul in Jupyter-Notebooks eventuell nicht so gut funktioniert, kann es von Vorteil sein, `turtle` über die Kommandozeile aufzurufen. Dies ist prinzipell auf allen Betriebssystemen möglich, aber auf Linux und MacOS deutlich einfacher als auf Windows.
Da das `turtle`-Modul in Jupyter-Notebooks eventuell nicht so gut funktioniert, kann es von Vorteil sein, `turtle` über die Kommandozeile aufzurufen. Dies ist prinzipell auf allen Betriebssystemen möglich, aber auf Linux und MacOS deutlich einfacher als auf Windows.
Falls Sie Linux nutzen, sollte Python bereits installiert sein. Um das gewünschte Programm zu öffnen tuen Sie folgendes:
Falls Sie Linux nutzen, sollte Python bereits installiert sein. Um das gewünschte Programm zu öffnen tun Sie folgendes:
1. Speichern Sie das Programm, das sie aufrufen möchten als PythonProgramm (.py)
1. Speichern Sie das Programm, das sie aufrufen möchten als Python-Programm mit der Dateiendung `.py`.
2. Öffnen Sie die Kommandozeile
2. Öffnen Sie die Kommandozeile.
3. Gehen Sie entweder in das Verzeichnis, in dem das Programm gespeichert ist, dafür geben Sie `cd /pfad/zum/verzeichnis` ein.
3. Gehen Sie in das Verzeichnis, in dem das Programm gespeichert ist. Geben Sie dafür `cd /pfad/zum/verzeichnis` ein.
4. Geben Sie auf der Kommandozeile `python programm.py` ein
4. Geben Sie auf der Kommandozeile `python programm.py` ein
5. Alternativ können Sie auch `python /pfad/zum/verzeichnis/programm.py` eingeben.
5. Alternativ können Sie auch direkt `python /pfad/zum/verzeichnis/programm.py` eingeben.
Falls Sie MacOS verwenden, gehen Sie folgendermaßen vor:
Falls Sie MacOS verwenden, gehen Sie folgendermaßen vor:
1. Speichern Sie das Programm, dass Sie aufrufen möchten als PythonProgramm (.py)
1. Speichern Sie das Programm, dass Sie aufrufen möchten als Python-Programm mit der Dateiendug `.py`.
2. Öffnen Sie das Terminal
2. Öffnen Sie das Terminal
3. Gehen Sie in das Verzeichnis, in welchem das Programm gespeichert ist, indem sie `cd pfad/zum/verzeichnis`eingeben
3. Gehen Sie in das Verzeichnis, in welchem das Programm gespeichert ist, indem sie `cd /pfad/zum/verzeichnis`eingeben
4. Geben Sie im Termial`python programm.py` ein.
4. Geben Sie im Termial`python programm.py` ein.
Falls Sie Windows verwenden, brauchen Sie beim ersten Aufruf etwas länger und müssen zusätzliche Schritte vornehmen, bei weiterer Verwendung springen Sie direkt zu Punkt 2 der Anleitung:
Falls Sie Windows verwenden, brauchen Sie beim ersten Aufruf etwas länger und müssen zusätzliche Schritte vornehmen, bei weiterer Verwendung springen Sie direkt zu Punkt 2 der Anleitung:
1. Fügen Sie Python zur PATH-Umgebung hinzu:
1. Fügen Sie Python zur PATH-Umgebung hinzu:
1.1. Finden Sie heraus wo Anaconda und Python gespeichert sind. (Dafür geben sie im Anaconda Prompt `where anaconda`und `where python` ein)
1.1. Finden Sie heraus wo Anaconda und Python gespeichert sind. (Dafür geben sie im Anaconda Prompt `where anaconda`und `where python` ein.)
1.2. Öffnen Sie den Explorer und öffnen Sie das Rechtsklick-Menü von `Dieser PC`
1.2. Öffnen Sie den Explorer und öffnen Sie das Rechtsklick-Menü von `Dieser PC`
1.3. Wählen Sie Eigenschaften
1.3. Wählen Sie Eigenschaften
1.4. Wählen Sie Erweiterte Systemeinstellungen
1.4. Wählen Sie Erweiterte Systemeinstellungen
1.5. Wählen Sie Umgebungsvariablen
1.5. Wählen Sie Umgebungsvariablen
1.6. Klicken Sie `Path`im unteren fenster an und dann auf `bearbeiten`
1.6. Klicken Sie `Path`im unteren Fenster an und dann auf `bearbeiten`
1.7. Klicken Sie auf `neu`und fügen Sie den Pfad für `Anaconda` hinzu, aber lassen Sie `anaconda.exe` weg
1.7. Klicken Sie auf `neu`und fügen Sie den Pfad für `Anaconda` hinzu, aber lassen Sie `anaconda.exe` weg
1.8. Wiederholen Sie dasselbe analog für den `Python`Pfad, dabei lassen Sie `python.exe` weg.
1.8. Wiederholen Sie dasselbe analog für den `Python`-Pfad, dabei lassen Sie `python.exe` weg.
1.9. Klicken Sie 2 mal okay und schließen Sie die Systemsteuerung
1.9. Klicken Sie zwei mal okay und schließen Sie die Systemsteuerung
1.10. Öffnen Sie die Kommandozeile (`cmd` in der Suchleiste eingeben und `enter` drücken) und geben sie `python` oder `python.exe` ein. Wenn Sie Erfolg hatten, öffnet sich Python und Sie könnten in der Kommandozeile programmieren.
1.10. Öffnen Sie die Kommandozeile (`cmd` in der Suchleiste eingeben und `enter` drücken) und geben sie `python` oder `python.exe` ein. Wenn Sie Erfolg hatten, öffnet sich Python und Sie können in der Kommandozeile programmieren.
1.11. Verlassen Sie `python` indem sie `exit()` eingeben.
1.11. Verlassen Sie `python` indem sie `exit()` eingeben.
2. Speichern Sie das Programm, das sie aufrufen möchten als PythonProgramm (.py)
2. Speichern Sie das Programm, das sie aufrufen möchten als Python-Programm mit der Dateiendung `.py`.
3. Geben Sie in der Kommandozeile `python.exe` und den Pfad zu Ihrem Programm ein (also `C:\Users\IhrName\Documents\nested\programm.py`)
3. Geben Sie in der Kommandozeile `python.exe` und den Pfad zu Ihrem Programm ein (also `C:\Users\IhrName\Documents\nested\programm.py`)
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
### 4.1 Das `turtle`-Modul
### 4.1 Das `turtle`-Modul
Führen Sie den folgenden Code aus, um zu testen, ob das `turtle`-Modul installiert ist:
Führen Sie den folgenden Code aus, um zu testen, ob das `turtle`-Modul installiert ist:
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
import turtle
import turtle
bob = turtle.Turtle()
bob = turtle.Turtle()
turtle.mainloop()
turtle.mainloop()
turtle.bye()
turtle.bye()
```
```
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
Es sollte sich ein Fenster öffnen, in dem ein kleiner Pfeil zu sehen ist -- dieser repräsentiert die Schildkröte ("turtle"). Schließen Sie das Fenster.
Es sollte sich ein Fenster öffnen, in dem ein kleiner Pfeil zu sehen ist -- dieser repräsentiert die Schildkröte ("turtle"). Schließen Sie das Fenster. (Danach erscheint ggf. eine Fehlermeldung -- nicht erschrecken, diese ist im Allgemeinen harmlos.)
*(Hinweis: In Jupyter gibt es manchmal Probleme mit dem `turtle`-Modul. Dann hilft es, das Turtle-Fenster zu schließen und den Code nochmal auszuführen oder im Kernel-Menü den Punkt "Restart & Clear Output" aufzurufen. Wenn es gar nicht klappt, dann nutzen Sie für die Turtle-Programmierung bitte nicht Jupyter-Notebooks, sondern Python-Dateien und führen diese direkt mit Python aus.
*(Hinweis: In Jupyter gibt es manchmal Probleme mit dem `turtle`-Modul. **Wichtig ist, dass Sie stets das Turtle-Fenster schließen.** Manchmal hilft es, den Code nochmal auszuführen oder im Kernel-Menü den Punkt "Restart & Clear Output" aufzurufen. Wenn es gar nicht klappt, dann nutzen Sie für die Turtle-Programmierung bitte nicht Jupyter-Notebooks, sondern Python-Dateien und führen diese direkt mit Python aus.
Manchmal vergisst Jupyter Notebooks auch, dass bereits eine Schildkröte existiert, in diesem Fall initialisieren Sie diese bitte einfach am Anfang des gewünschten Code-Blocks)*
Manchmal vergisst Jupyter Notebooks auch, dass bereits eine Schildkröte existiert, in diesem Fall initialisieren Sie diese bitte einfach am Anfang des gewünschten Code-Blocks)*
Probieren Sie nun folgendes (am besten in einem eigenen Jupyter-Notebook, einer eigenen Python-Datei, oder im folgenden Block, den Sie dann schrittweise ergänzen):
Probieren Sie nun folgendes (am besten in einem eigenen Jupyter-Notebook, einer eigenen Python-Datei, oder im folgenden Block, den Sie dann schrittweise ergänzen):
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
import turtle
import turtle
bob = turtle.Turtle()
bob = turtle.Turtle()
print(bob)
print(bob)
bob.fd(100)
bob.fd(100)
turtle.mainloop()
turtle.mainloop()
turtle.bye()
turtle.bye()
```
```
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
```
```
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
Das `turtle`-Modul (mit kleinem `t`) stellt eine Funktion `Turtle` (mit großem `T`) bereit, die ein Turtle-Objekt erzeugt - dieses weisen wir einer Variable mit dem Namen `bob` zu. Wenn wir `bob` mit `print` ausgeben, erhalten wir eine Ausgabe ähnlich
Das `turtle`-Modul (mit kleinem `t`) stellt eine Funktion `Turtle` (mit großem `T`) bereit, die ein Turtle-Objekt erzeugt -- dieses weisen wir einer Variable mit dem Namen `bob` zu. Wenn wir `bob` mit `print` ausgeben, erhalten wir eine Ausgabe ähnlich
```
```
<turtle.Turtleobjectat0xb7bfbf4c>
<turtle.Turtleobjectat0xb7bfbf4c>
```
```
Das bedeutet, dass `bob` auf ein Objekt vom Typ `Turtle` verweist, wie es im `turtle`-Modul definiert wurde.
Das bedeutet, dass `bob` auf ein Objekt vom Typ `Turtle` verweist, wie es im `turtle`-Modul definiert wurde.
Der Aufruf von `mainloop` weist das Fenster an, auf Nutzeraktivität zu warten. In diesem Fall kann man als NutzerIn allerdings kaum mehr tun, als das Fenster zu schließen.
Der Aufruf von `mainloop` weist das Fenster an, auf Nutzeraktivität zu warten. In diesem Fall kann man als NutzerIn allerdings kaum mehr tun, als das Fenster zu schließen.
Sobald wir eine Schildkröte erzeugt haben, können wir eine **Methode** aufrufen, um die Schildkröte im Fenster zu bewegen. Eine Methode ist einer Funktion ähnlich, aber die Syntax ist etwas anders. Zum Beispiel können wir die Schildkröte mit dem Aufruf von
Sobald wir eine Schildkröte erzeugt haben, können wir eine **Methode** aufrufen, um die Schildkröte im Fenster zu bewegen. Eine Methode ist einer Funktion ähnlich, aber die Syntax ist etwas anders. Zum Beispiel können wir die Schildkröte mit dem Aufruf von
```python
```python
bob.fd(100)
bob.fd(100)
```
```
nach vorne bewegen. Die Methode `fd` gehört zu dem Turtle-Objekt welches wir `bob` nennen. Wenn wir die Methode aufrufen, bitten wir `bob` nach vorne zu gehen (**f**orwar**d**).
nach vorne bewegen. Die Methode `fd` gehört zu dem Turtle-Objekt welches wir `bob` nennen. Wenn wir die Methode aufrufen, bitten wir `bob` nach vorne zu gehen (**f**orwar**d**).
Das Argument von `fd` ist eine Strecke in Pixeln (den Bildpunkten auf dem Monitor), daher hängt die Entfernung, die `bob` geht, von unserer Monitorauflösung ab.
Das Argument von `fd` ist eine Strecke in Pixeln (den Bildpunkten auf dem Monitor), daher hängt die Entfernung, die `bob` geht, von unserer Monitorauflösung ab.
Andere Methoden, die wir auf einer Schildkröte aufrufen können sind `bk` für eine Rückwärtsbewegung (**b**ac**k**ward), `lt` für eine Linksdrehung (**l**eft **t**urn) und `rt` für eine Rechtsdrehung (**r**ight **t**urn). Das Argument für `lt` und `rt` ist ein Winkel in Grad.
Andere Methoden, die wir auf einer Schildkröte aufrufen können sind `bk` für eine Rückwärtsbewegung (**b**ac**k**ward), `lt` für eine Linksdrehung (**l**eft **t**urn) und `rt` für eine Rechtsdrehung (**r**ight **t**urn). Das Argument für `lt` und `rt` ist ein Winkel in Grad.
Jede Schildkröte hat außerdem einen "Stift", der entweder "oben" oder "unten" ist. Wenn der Stift unten ist, berührt der Stift sozusagen das Papier und die Schildkröte hinterlässt eine Spur wenn sie sich bewegt. Die Methoden `pu` und `pd` stehen für "Stift hoch" (**p**en **u**p) und "Stift herunter" (**p**en **d**own).
Jede Schildkröte hat außerdem einen "Stift", der entweder "oben" oder "unten" ist. Wenn der Stift unten ist, berührt der Stift sozusagen das Papier und die Schildkröte hinterlässt eine Spur wenn sie sich bewegt. Die Methoden `pu` und `pd` stehen für "Stift hoch" (**p**en **u**p) und "Stift herunter" (**p**en **d**own).
Fügen Sie die folgenden Zeilen zu Ihrem Programm hinzu, um einen rechten Winkel zu zeichnen (nachdem Sie `bob` erzeugt haben und bevor Sie `mainloop` aufrufen):
Fügen Sie die folgenden Zeilen zu Ihrem Programm hinzu, um einen rechten Winkel zu zeichnen (nachdem Sie `bob` erzeugt haben und bevor Sie `mainloop` aufrufen):
```python
```python
bob.fd(100)
bob.fd(100)
bob.lt(90)
bob.lt(90)
bob.fd(100)
bob.fd(100)
```
```
Wenn Sie dieses Programm ausführen, sollte sich `bob` zunächst nach Osten und dann nach Norden bewegen und dabei zwei Strecken zeichnen.
Wenn Sie dieses Programm ausführen, sollte sich `bob` zunächst nach Osten und dann nach Norden bewegen und dabei zwei Strecken zeichnen.
Verändern Sie ihr Programm jetzt, so dass `bob` ein Quadrat zeichnet. Fahren Sie erst mit dem Kurs fort, wenn es funktioniert.
Verändern Sie ihr Programm jetzt, so dass `bob` ein Quadrat zeichnet. Fahren Sie erst mit dem Kurs fort, wenn es funktioniert.
Wir können das gleiche deutlich knapper mit einer `for`-Schleife formulieren. Testen Sie folgendes:
Wir können das gleiche deutlich knapper mit einer `for`-Schleife formulieren. Testen Sie folgendes:
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
for i in range(4):
for i in range(4):
print('Hello!')
print('Hello!')
```
```
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
Sie sollten folgende Ausgabe sehen:
Sie sollten folgende Ausgabe sehen:
```
```
Hello!
Hello!
Hello!
Hello!
Hello!
Hello!
Hello!
Hello!
```
```
Das ist die einfachste Art und Weise, eine `for`-Schleife zu verwenden. Wir werden uns das später ausführlicher anschauen, aber das sollte reichen, damit Sie ihr Programm zum Zeichnen eines Quadrats vereinfachen können. Bitte fahren Sie erst fort, wenn Sie ihr Programm mit Hilfe der `for`-Schleife vereinfacht haben.
Das ist die einfachste Art und Weise, eine `for`-Schleife zu verwenden. Wir werden uns das später ausführlicher anschauen, aber das sollte reichen, damit Sie ihr Programm zum Zeichnen eines Quadrats vereinfachen können. Bitte fahren Sie erst fort, wenn Sie ihr Programm mit Hilfe der `for`-Schleife vereinfacht haben.
Dieser Code ist etwas anders als der vorherige Code zum Zeichnen eines Quadrats. Nachdem die letzte Seite des Quadrats gezeichnet wird, wird noch eine 90° Drehung durchgeführt. Diese zusätzliche Drehung kostet etwas Zeit, aber der Code ist einfacher, wenn in jedem Schleifendurchlauf die gleiche Folge von Anweisungen ausgeführt wird. Ein Nebeneffekt ist, dass die Schildkröte am Ende wieder in der Ausgangsposition mit Blick zur Ausgangsrichtung steht.
Dieser Code ist etwas anders als der vorherige Code zum Zeichnen eines Quadrats. Nachdem die letzte Seite des Quadrats gezeichnet wird, wird noch eine 90° Drehung durchgeführt. Diese zusätzliche Drehung kostet etwas Zeit, aber der Code ist einfacher, wenn in jedem Schleifendurchlauf die gleiche Folge von Anweisungen ausgeführt wird. Ein Nebeneffekt ist, dass die Schildkröte am Ende wieder in der Ausgangsposition mit Blick zur Ausgangsrichtung steht.
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
### 4.3 Übungen
### 4.3 Übungen
In den folgenden Abschnitten folgen einige Übungen zur "Schildkrötenwelt". Sie sollten Ihnen Spaß bereiten, habe aber auch einen Sinn. Versuchen Sie diesen herauszufinden und gehen Sie Abschnittweise vor.
In den folgenden Abschnitten folgen einige Übungen zur "Schildkrötenwelt". Sie sollten Ihnen Spaß bereiten, habe aber auch einen Sinn. Versuchen Sie diesen herauszufinden und gehen Sie Abschnittweise vor.
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
### 4.4 Verkapselung
### 4.4 Verkapselung
- **Aufgabe 1:** Schreiben Sie eine Funktion `square`, die einen Parameter namens `t` erwartet, welcher eine Schildkröte ist. Die Funktion soll die Schildkröte nutzen, um ein Quadrat zu zeichnen.
- **Aufgabe 1:** Schreiben Sie eine Funktion `square`, die einen Parameter namens `t` erwartet, welcher eine Schildkröte ist. Die Funktion soll die Schildkröte nutzen, um ein Quadrat zu zeichnen.
- **Aufgabe 2:** Schreiben Sie einen Funktionsaufruf, der `bob` als Argument an `square` übergibt und rufen Sie ihr Programm auf.
- **Aufgabe 2:** Schreiben Sie einen Funktionsaufruf, der `bob` als Argument an `square` übergibt und rufen Sie ihr Programm auf.
In der ersten Aufgabe sollten Sie den Code zum Zeichnen eines Quadrates in eine Funktion packen und dann in Aufgabe 2 die Funktion aufrufen, indem Sie eine Schildkröte als Argument an die Funktion übergeben. So könnte eine mögliche Lösung aussehen:
In der ersten Aufgabe sollten Sie den Code zum Zeichnen eines Quadrates in eine Funktion packen und dann in Aufgabe 2 die Funktion aufrufen, indem Sie eine Schildkröte als Argument an die Funktion übergeben. So könnte eine mögliche Lösung aussehen:
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
def square(t):
def square(t):
for i in range(4):
for i in range(4):
t.fd(100)
t.fd(100)
t.lt(90)
t.lt(90)
square(bob)
square(bob)
```
```
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
Die beiden innersten Anweisungen (`t.fd` und `t.lt`) sind doppelt eingerückt, weil sie innerhalb der `for`-Schleife sind, die wiederrum innerhalb der Funktionsdefinition steht. Die übernächste Zeile (`square(bob)`) ist wieder bündig mit dem linken Rand ausgerichtet, also sowohl außerhalb der `for`-Schleife, als auch außerhalb der Funktionsdefinition.
Die beiden innersten Anweisungen (`t.fd` und `t.lt`) sind doppelt eingerückt, weil sie innerhalb der `for`-Schleife sind, die wiederrum innerhalb der Funktionsdefinition steht. Die übernächste Zeile (`square(bob)`) ist wieder bündig mit dem linken Rand ausgerichtet, also sowohl außerhalb der `for`-Schleife, als auch außerhalb der Funktionsdefinition.
Innerhalb der Funktion verweist `t` auf die gleiche Schildkröte `bob`, so dass `t.lt(90)` die gleiche Auswirkung hat wie `bob.lt(90)`. Hätten wir dann in der Funktion nicht direkt `bob` aufrufen können oder den Parameter stattdessen `bob` nennen können? Prinzipiell schon, aber die Idee ist, dass `t` irgendeine Schildkröte sein kann, nicht nur `bob`, so dass wir beispielsweise eine zweite Schildkröte erzeugen und sie als Argument an `square` übergeben können:
Innerhalb der Funktion verweist `t` auf die gleiche Schildkröte `bob`, so dass `t.lt(90)` die gleiche Auswirkung hat wie `bob.lt(90)`. Hätten wir dann in der Funktion nicht direkt `bob` aufrufen können oder den Parameter stattdessen `bob` nennen können? Prinzipiell schon, aber die Idee ist, dass `t` irgendeine Schildkröte sein kann, nicht nur `bob`, so dass wir beispielsweise eine zweite Schildkröte erzeugen und sie als Argument an `square` übergeben können:
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
alice = turtle.Turtle()
alice = turtle.Turtle()
square(alice)
square(alice)
```
```
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
Ein Stück Quellcode in eine Funktion zu packen, nennt man "Verkapselung" (Englisch: *encapsulation*). Ein Vorteil der Verkapselung ist, dass für ein Stück Code ein Name vergeben wird, der wie eine Art Dokumentation wirkt, also sagt, was der Code macht. Ein anderer Vorteil ist, dass wir den Code leicht wiederverwenden können, denn es ist deutlich praktischer, eine Funktion zweimal aufzurufen, als den Quellcode im Funktionsrumpf zu kopieren.
Ein Stück Quellcode in eine Funktion zu packen, nennt man "Verkapselung" (Englisch: *encapsulation*). Ein Vorteil der Verkapselung ist, dass für ein Stück Code ein Name vergeben wird, der wie eine Art Dokumentation wirkt, also sagt, was der Code macht. Ein anderer Vorteil ist, dass wir den Code leicht wiederverwenden können, denn es ist deutlich praktischer, eine Funktion zweimal aufzurufen, als den Quellcode im Funktionsrumpf zu kopieren.
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
### 4.5 Verallgemeinerung
### 4.5 Verallgemeinerung
- **Aufgabe 3:** Ergänzen Sie die Funktion `square` um einen weiteren Parameter namens `length`. Ändern Sie den Rumpf der Funktion so, dass dass die Seitenlänge des gezeichneten Quadrats `length` entspricht. Passen Sie dann den Funktionsaufruf an, sodass ein weiteres Argument als Länge übergeben wird. Starten Sie ihr Programm noch einmal und testen Sie es mit verschiedenen Werten für die Länge. *(Hinweis: Kopieren Sie die Funktion aus dem vorherigen Abschnitt oder arbeiten Sie in dem bereits geschriebenen Code)*
- **Aufgabe 3:** Ergänzen Sie die Funktion `square` um einen weiteren Parameter namens `length`. Ändern Sie den Rumpf der Funktion so, dass dass die Seitenlänge des gezeichneten Quadrats `length` entspricht. Passen Sie dann den Funktionsaufruf an, sodass ein weiteres Argument als Länge übergeben wird. Starten Sie ihr Programm noch einmal und testen Sie es mit verschiedenen Werten für die Länge. *(Hinweis: Kopieren Sie die Funktion aus dem vorherigen Abschnitt oder arbeiten Sie in dem bereits geschriebenen Code)*
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
```
```
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
Der nächste Schritt ist, einen Parameter `length` zu `square` hinzuzufügen. Hier ist eine Lösung:
Der nächste Schritt ist, einen Parameter `length` zu `square` hinzuzufügen. Hier ist eine Lösung:
Das Hinzufügen des Parameters stellt eine **Verallgemeinerung** dar; denn die Funktion wird dadurch allgemeiner: vorher hatte das gezeichnete Quadrat immer die gleiche Größe, jetzt kann es jede beliebige Größe haben.
Das Hinzufügen des Parameters stellt eine **Verallgemeinerung** dar; denn die Funktion wird dadurch allgemeiner: vorher hatte das gezeichnete Quadrat immer die gleiche Größe, jetzt kann es jede beliebige Größe haben.
- **Aufgabe 4:** Kopieren Sie die Definition der Funktion `square` und benennen Sie die Kopie in `polygon` um. Fügen Sie einen weiteren Parameter namens `n` hinzu und ändern Sie den Funktionsrumpf so, dass ein n-seitiges [reguläres Vieleck](https://de.wikipedia.org/wiki/Regelm%C3%A4%C3%9Figes_Polygon) (Polygon) gezeichnet wird. *(Hinweis: Die Außenwinkel eines n-seitigen Vielecks betragen 360/n Grad.)*
- **Aufgabe 4:** Kopieren Sie die Definition der Funktion `square` und benennen Sie die Kopie in `polygon` um. Fügen Sie einen weiteren Parameter namens `n` hinzu und ändern Sie den Funktionsrumpf so, dass ein n-seitiges [reguläres Vieleck](https://de.wikipedia.org/wiki/Regelm%C3%A4%C3%9Figes_Polygon) (Polygon) gezeichnet wird. *(Hinweis: Die Außenwinkel eines n-seitigen Vielecks betragen 360/n Grad.)*
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
```
```
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
Der nächste Schritt ist ebenfalls eine Verallgemeinerung. Anstatt eines Quadrates kann die Funktion `polygon` reguläre Vielecke mit beliebig vielen Seiten zeichnen. So könnte eine Lösung aussehen:
Der nächste Schritt ist ebenfalls eine Verallgemeinerung. Anstatt eines Quadrates kann die Funktion `polygon` reguläre Vielecke mit beliebig vielen Seiten zeichnen. So könnte eine Lösung aussehen:
Dieses Beispiel zeichnet ein siebenseitiges Vieleck mit einer Seitenlänge von 70.
Dieses Beispiel zeichnet ein siebenseitiges Vieleck mit einer Seitenlänge von 70.
Bei einer Funktion mit mehr als nur ein paar Argumenten kann man leicht vergessen, was die Argumente bedeuten oder in welcher Reihenfolge sie angegeben werden müssen. In diesem Fall ist es eine gute Idee, die Namen der Parameter in der Argumentliste explizit anzugeben:
Bei einer Funktion mit mehr als nur ein paar Argumenten kann man leicht vergessen, was die Argumente bedeuten oder in welcher Reihenfolge sie angegeben werden müssen. In diesem Fall ist es eine gute Idee, die Namen der Parameter in der Argumentliste explizit anzugeben:
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
polygon(bob, n=7, length=70)
polygon(bob, n=7, length=70)
```
```
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
Diese werden **Schlüsselwortargumente** genannt, denn Sie enthalten die Parameter als "Schlüsselwörter" (diese sollten nicht mit Python-Schlüsselwörtern wie z.B. `while` oder `def` verwechselt werden).
Diese werden **Schlüsselwortargumente** genannt, denn Sie enthalten die Parameter als "Schlüsselwörter" (diese sollten nicht mit Python-Schlüsselwörtern wie z.B. `while` oder `def` verwechselt werden).
Durch diese Syntax wird das Programm lesbarer. Sie erinnert uns auch daran, wie Argumente und Parameter funktionieren: wenn wir eine Funktion aufrufen, werden unsere Argumente den Parametern zugewiesen.
Durch diese Syntax wird das Programm lesbarer. Sie erinnert uns auch daran, wie Argumente und Parameter funktionieren: wenn wir eine Funktion aufrufen, werden unsere Argumente den Parametern zugewiesen.
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
### 4.6 Schnittstellenentwurf
### 4.6 Schnittstellenentwurf
- **Aufgabe 5:** Schreiben Sie eine Funktion `circle` die eine Schildkröte `t` und einen Radius `r` als Parameter erwartet und annähernd einen Kreis zeichnet, indem sie die Funktion `polygon` mit einer geeigneten Seitenlänge und Anzahl von Seiten aufruft. Testen Sie ihre Funktion mit verschiedenen Werten für `r`.
- **Aufgabe 5:** Schreiben Sie eine Funktion `circle` die eine Schildkröte `t` und einen Radius `r` als Parameter erwartet und annähernd einen Kreis zeichnet, indem sie die Funktion `polygon` mit einer geeigneten Seitenlänge und Anzahl von Seiten aufruft. Testen Sie ihre Funktion mit verschiedenen Werten für `r`.
*(Hinweis: Finden Sie den Umfang des Kreises heraus und stellen Sie sicher, dass `length * n` gleich dem Umfang ist.)*
*(Hinweis: Finden Sie den Umfang des Kreises heraus und stellen Sie sicher, dass `length * n` gleich dem Umfang ist.)*
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
```
```
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
Der nächste Schritt ist, eine Funktion `circle` zu schreiben, die einen Radius `r` als Parameter erwartet. Hier eine einfache Lösung, die die Funktion `polygon` nutzt, um ein reguläres 50-seitiges Vieleck zu zeichnen:
Der nächste Schritt ist, eine Funktion `circle` zu schreiben, die einen Radius `r` als Parameter erwartet. Hier eine einfache Lösung, die die Funktion `polygon` nutzt, um ein reguläres 50-seitiges Vieleck zu zeichnen:
Die erste Zeile berechnet den Umfang eines Kreises mit dem Radius `r` mit Hilfe der Formel 2 π r. Da wir `math.pi` nutzen wollen, müssen wir zunächst `math` importieren. Die Konvention ist, dass `import`-Anweisungen stets am Anfang eines Python-Programms stehen.
Die erste Zeile berechnet den Umfang eines Kreises mit dem Radius `r` mit Hilfe der Formel 2 π r. Da wir `math.pi` nutzen wollen, müssen wir zunächst `math` importieren. Die Konvention ist, dass `import`-Anweisungen stets am Anfang eines Python-Programms stehen.
Weil `n` die Anzahl der Liniensegmente in unserer Näherung eines Kreises ist, ist `length` die Länge jedes einzelnen Segmentes. Daher zeichnet `polygon` ein reguläre 50-seitiges Vieleck als Näherun eines Kreises mit Radius `r`.
Weil `n` die Anzahl der Liniensegmente in unserer Näherung eines Kreises ist, ist `length` die Länge jedes einzelnen Segmentes. Daher zeichnet `polygon` ein reguläre 50-seitiges Vieleck als Näherun eines Kreises mit Radius `r`.
Eine Beschränkung dieser Lösung ist, dass `n` eine Konstante ist. Daher sind für sehr große Kreise die Liniensegmente zu lang und für kleine Kreise verschwenden wir Zeit mit dem Zeichnen sehr kleiner Segmente. Eine Lösung wäre, die Funktion zu verallgemeinern und `n` als Parameter hinzuzufügen. Dies gäbe dem Nutzer (wer auch immer `circle` aufruft) mehr Kontrolle, aber die Schnittstelle wäre weniger aufgeräumt.
Eine Beschränkung dieser Lösung ist, dass `n` eine Konstante ist. Daher sind für sehr große Kreise die Liniensegmente zu lang und für kleine Kreise verschwenden wir Zeit mit dem Zeichnen sehr kleiner Segmente. Eine Lösung wäre, die Funktion zu verallgemeinern und `n` als Parameter hinzuzufügen. Dies gäbe dem Nutzer (wer auch immer `circle` aufruft) mehr Kontrolle, aber die Schnittstelle wäre weniger aufgeräumt.
Die **Schnittstelle** (Englisch *Interface*) einer Funktion ist eine Zusammenfassung dessen, wie die Funktion genutzt wird: Was sind ihre Parameter? Was macht die Funktion? Was ist ihr Rückgabewert? etc. Eine Schnittstelle ist "aufgeräumt", wenn sie der/m Aufrufenden ermöglicht das zu tun, was er oder sie möchte, ohne sich mit unnötigen Details beschäftigen zu müssen.
Die **Schnittstelle** (Englisch *Interface*) einer Funktion ist eine Zusammenfassung dessen, wie die Funktion genutzt wird: Was sind ihre Parameter? Was macht die Funktion? Was ist ihr Rückgabewert? etc. Eine Schnittstelle ist "aufgeräumt", wenn sie der/m Aufrufenden ermöglicht das zu tun, was er oder sie möchte, ohne sich mit unnötigen Details beschäftigen zu müssen.
In unserem Beispiel gehört `r` zur Schnittstelle, da es den Kreis beschreibt, der gezeichnet werden soll. Dagegen ist `n` weniger passend, denn es gehört zu den Details, wie der Kreis gezeichnet wird.
In unserem Beispiel gehört `r` zur Schnittstelle, da es den Kreis beschreibt, der gezeichnet werden soll. Dagegen ist `n` weniger passend, denn es gehört zu den Details, wie der Kreis gezeichnet wird.
Anstatt die Schnittstelle zu "verunreinigen" ist es besser, einen passenden Wert für `n` in Abhängigkeit vom Umfang des Kreises zu wählen:
Anstatt die Schnittstelle zu "verunreinigen" ist es besser, einen passenden Wert für `n` in Abhängigkeit vom Umfang des Kreises zu wählen:
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
def circle(t, r):
def circle(t, r):
circumference = 2 * math.pi * r
circumference = 2 * math.pi * r
n = int(circumference / 3) + 3
n = int(circumference / 3) + 3
length = circumference / n
length = circumference / n
polygon(t, n, length)
polygon(t, n, length)
```
```
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
Jetzt ist die Anzahl der Liniensegmente eine ganze Zahl, die nah bei Umfang/3 liegt, sodass die Länge jedes Segments ungefähr 3 beträgt. Das ist klein genug, damit der Kreis gut aussieht, aber auch groß genug, um eine effiziente Zeichnung zu ermöglichen und passt daher für jede Größe von Kreis.
Jetzt ist die Anzahl der Liniensegmente eine ganze Zahl, die nah bei Umfang/3 liegt, sodass die Länge jedes Segments ungefähr 3 beträgt. Das ist klein genug, damit der Kreis gut aussieht, aber auch groß genug, um eine effiziente Zeichnung zu ermöglichen und passt daher für jede Größe von Kreis.
Wir addieren 3, damit das Vieleck mindestens drei Seiten hat.
Wir addieren 3, damit das Vieleck mindestens drei Seiten hat.
### 4.7 Refactoring
### 4.7 Refactoring
- **Aufgabe 6:** Schreiben Sie eine verallgemeinerte Funktion `circle`, die Sie `arc` nennen. Diese soll ein weiteres Argument `angle` erwartet, welches angibt, welcher Anteil des Kreises gezeichnet werden soll. Die Funktion `arc` soll also einen Kreisbogen zeichnen. Der Wert von `angle` ist dabei in Grad, so dass für `angle=360` ein vollständiger Kreis gezeichnet werden sollte.
- **Aufgabe 6:** Schreiben Sie eine verallgemeinerte Funktion `circle`, die Sie `arc` nennen. Diese soll ein weiteres Argument `angle` erwartet, welches angibt, welcher Anteil des Kreises gezeichnet werden soll. Die Funktion `arc` soll also einen Kreisbogen zeichnen. Der Wert von `angle` ist dabei in Grad, so dass für `angle=360` ein vollständiger Kreis gezeichnet werden sollte.
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
```
```
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
Als wir `circle` geschrieben haben, konnten wir `polygon` wiederverwenden, denn ein regelmäßiges Vieleck mit vielen Seiten ist eine gute Näherung für einen Kreis. Aber mit der Funktion `arc` klappt das nicht so einfach - wir können kein Vieleck und keinen Kreis nutzen, um einen Kreisbogen zu zeichnen.
Als wir `circle` geschrieben haben, konnten wir `polygon` wiederverwenden, denn ein regelmäßiges Vieleck mit vielen Seiten ist eine gute Näherung für einen Kreis. Aber mit der Funktion `arc` klappt das nicht so einfach - wir können kein Vieleck und keinen Kreis nutzen, um einen Kreisbogen zu zeichnen.
Eine Alternative ist, mit einer Kopie von `polygon` zu beginnen und diese zu `arc` zu verändern. Das Ergebnis könnte so aussehen:
Eine Alternative ist, mit einer Kopie von `polygon` zu beginnen und diese zu `arc` zu verändern. Das Ergebnis könnte so aussehen:
Die zweite Hälfte dieser Funktion sieht aus wie `polygon`, aber wir können `polygon` nicht einfach wiederverwenden ohne die Schnittstelle zu verändern. Wir könnten `polygon` generalisieren, so dass es einen Winkel als ein weiteres Argument erwartet, aber dann wäre `polygon` kein angemessener Name mehr. Nennen wir diese verallgemeinerte Funktion also stattdessen `polyline`:
Die zweite Hälfte dieser Funktion sieht aus wie `polygon`, aber wir können `polygon` nicht einfach wiederverwenden ohne die Schnittstelle zu verändern. Wir könnten `polygon` generalisieren, so dass es einen Winkel als ein weiteres Argument erwartet, aber dann wäre `polygon` kein angemessener Name mehr. Nennen wir diese verallgemeinerte Funktion also stattdessen `polyline`:
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
def polyline(t, n, length, angle):
def polyline(t, n, length, angle):
for i in range(n):
for i in range(n):
t.fd(length)
t.fd(length)
t.lt(angle)
t.lt(angle)
```
```
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
Jetzt können wir die Funktionen `polygon` und `arc` umschreiben, sodass sie die Funktion `polyline` nutzen:
Jetzt können wir die Funktionen `polygon` und `arc` umschreiben, sodass sie die Funktion `polyline` nutzen:
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
def polygon(t, n, length):
def polygon(t, n, length):
angle = 360.0 / n
angle = 360.0 / n
polyline(t, n, length, angle)
polyline(t, n, length, angle)
def arc(t, r, angle):
def arc(t, r, angle):
arc_length = 2 * math.pi * r * angle / 360
arc_length = 2 * math.pi * r * angle / 360
n = int(arc_length / 3) + 1
n = int(arc_length / 3) + 1
step_length = arc_length / n
step_length = arc_length / n
step_angle = float(angle) / n
step_angle = float(angle) / n
polyline(t, n, step_length, step_angle)
polyline(t, n, step_length, step_angle)
```
```
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
Und schließlich können wir die Funktion `circle` umschreiben, sodass sie die Funktion `arc` nutzt:
Und schließlich können wir die Funktion `circle` umschreiben, sodass sie die Funktion `arc` nutzt:
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
def circle(t, r):
def circle(t, r):
arc(t, r, 360)
arc(t, r, 360)
```
```
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
Dieser Prozess der Umstrukturierung eines Programms und der Verbesserung von Schnittstellen nennt sich **Refactoring** und hilft Code wiederverwenden zu können. In unserem Fall haben wir festgestellt, dass `arc` und `polygon` ähnlichen Code enthalten haben, daher haben wir diesen Code umgestaltet und in die Funktion `polyline` "ausfaktorisiert" also quasi ausgeklammert.
Dieser Prozess der Umstrukturierung eines Programms und der Verbesserung von Schnittstellen nennt sich **Refactoring** und hilft Code wiederverwenden zu können. In unserem Fall haben wir festgestellt, dass `arc` und `polygon` ähnlichen Code enthalten haben, daher haben wir diesen Code umgestaltet und in die Funktion `polyline` "ausfaktorisiert" also quasi ausgeklammert.
Hätten wir vorausschauend geplant, hätten wir vielleicht `polyline` zuerst geschrieben und diese Umstrukturierung vermieden. Oft wissen wir aber am Anfang eines Projektes noch nicht genug, um schon alle Schnittstellen entwerfen zu können. Sobald wir anfangen zu programmieren, verstehen wir das Problem besser. Manchmal ist Refactoring ein Anzeichen dafür, dass wir etwas gelernt haben.
Hätten wir vorausschauend geplant, hätten wir vielleicht `polyline` zuerst geschrieben und diese Umstrukturierung vermieden. Oft wissen wir aber am Anfang eines Projektes noch nicht genug, um schon alle Schnittstellen entwerfen zu können. Sobald wir anfangen zu programmieren, verstehen wir das Problem besser. Manchmal ist Refactoring ein Anzeichen dafür, dass wir etwas gelernt haben.
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
### 4.8 Ein Entwicklungsplan
### 4.8 Ein Entwicklungsplan
Ein **Entwicklungsplan** ist ein Prozess zum Schreiben von Programmen. Der Prozess, den wir in dieser Fallstudie verwendet haben ist "Verkapselung und Verallgemeinerung". Die Schritte dieses Prozesses sind:
Ein **Entwicklungsplan** ist ein Prozess zum Schreiben von Programmen. Der Prozess, den wir in dieser Fallstudie verwendet haben ist "Verkapselung und Verallgemeinerung". Die Schritte dieses Prozesses sind:
1. Wir schreiben ein kleines Programm ohne Funktionsdefinitionen.
1. Wir schreiben ein kleines Programm ohne Funktionsdefinitionen.
2. Sobald das Programm funktioniert, identifizieren wir ein schlüssiges und zusammengehöriges Stück Code, verkapseln es in einer Funktion und geben ihm einen Namen.
2. Sobald das Programm funktioniert, identifizieren wir ein schlüssiges und zusammengehöriges Stück Code, verkapseln es in einer Funktion und geben ihm einen Namen.
3. Wir verallgemeinern die Funktion durch Hinzufügen geeigneter Parameter.
3. Wir verallgemeinern die Funktion durch Hinzufügen geeigneter Parameter.
4. Wir wiederholen die Schritte 1 bis 3 bis wir eine Menge funktionierender Funktionen haben. Dabei kopieren wir Code und fügen ihn an der richtigen Stelle ein, um nochmaliges Eintippen zu vermeiden (und das damit ggf. verbundene Debugging).
4. Wir wiederholen die Schritte 1 bis 3 bis wir eine Menge funktionierender Funktionen haben. Dabei kopieren wir Code und fügen ihn an der richtigen Stelle ein, um nochmaliges Eintippen zu vermeiden (und das damit ggf. verbundene Debugging).
5. Wir suchen nach Möglichkeiten, das Programm durch Refactoring zu verbessern. Wenn wir beispielsweise ähnlichen Code an verschiedenen Stellen haben, können wir überlegen, ob wir ihn nicht besser in eine geeignete allgemeine Funktion ausklammern.
5. Wir suchen nach Möglichkeiten, das Programm durch Refactoring zu verbessern. Wenn wir beispielsweise ähnlichen Code an verschiedenen Stellen haben, können wir überlegen, ob wir ihn nicht besser in eine geeignete allgemeine Funktion ausklammern.
Dieser Prozess hat einige Nachteile (wir schauen uns Alternativen später an), aber er ist praktisch, wenn wir vorab nicht wissen, wie wir das Programm in Funktionen aufteilen könnten. Dieser Ansatz ermöglicht uns den Entwurf des Programms während wir es schreiben.
Dieser Prozess hat einige Nachteile (wir schauen uns Alternativen später an), aber er ist praktisch, wenn wir vorab nicht wissen, wie wir das Programm in Funktionen aufteilen könnten. Dieser Ansatz ermöglicht uns den Entwurf des Programms während wir es schreiben.
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
### 4.9 Docstring
### 4.9 Docstring
Ein **Docstring** ist eine Zeichenkette am Anfang einer Funktion, die die Schnittstelle der Funktion erklärt ("doc" ist kurz für "documentation", also Dokumentation). Hier ist ein Beispiel:
Ein **Docstring** ist eine Zeichenkette am Anfang einer Funktion, die die Schnittstelle der Funktion erklärt ("doc" ist kurz für "documentation", also Dokumentation). Hier ist ein Beispiel:
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
def polyline(t, n, length, angle):
def polyline(t, n, length, angle):
"""Draws n line segments with the given length and
"""Draws n line segments with the given length and
angle (in degrees) between them. t is a turtle.
angle (in degrees) between them. t is a turtle.
"""
"""
for i in range(n):
for i in range(n):
t.fd(length)
t.fd(length)
t.lt(angle)
t.lt(angle)
```
```
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
Es gilt die Konvention, dass Docstrings in dreifachen Anführungszeichen gesetzt werden. Mit Hilfe der dreifachen Anführungszeichen kann der Text über mehr als eine Zeile hinwegreichen.
Es gilt die Konvention, dass Docstrings in dreifachen Anführungszeichen gesetzt werden. Mit Hilfe der dreifachen Anführungszeichen kann der Text über mehr als eine Zeile hinwegreichen.
Der Docstring im Beispiel ist knapp, enthält aber die wesentlichen Informationen, die jemand benötigt, der die Funktion nutzen möchte. Es wird prägnant erklärt, was die Funktion tut (ohne groß zu beschreiben, wie sie das tut). Es wird auch erklärt, welche Auswirkung jeder Parameter auf das Verhalten der Funktion hat und von welchem Typ jeder Parameter sein sollte (falls es nicht offensichtlich ist).
Der Docstring im Beispiel ist knapp, enthält aber die wesentlichen Informationen, die jemand benötigt, der die Funktion nutzen möchte. Es wird prägnant erklärt, was die Funktion tut (ohne groß zu beschreiben, wie sie das tut). Es wird auch erklärt, welche Auswirkung jeder Parameter auf das Verhalten der Funktion hat und von welchem Typ jeder Parameter sein sollte (falls es nicht offensichtlich ist).
Das Schreiben dieser Art von Dokumentation ist ein wichtiger Teil des Schnittstellenentwurfs. Eine gut konzipierte Schnittstelle sollte einfach zu erklären sein. Falls es Ihnen schwerfällt, Ihre Funktionen zu erklären, dann könnte es vielleicht helfen, die Schnittstelle zu verbessern.
Das Schreiben dieser Art von Dokumentation ist ein wichtiger Teil des Schnittstellenentwurfs. Eine gut konzipierte Schnittstelle sollte einfach zu erklären sein. Falls es Ihnen schwerfällt, Ihre Funktionen zu erklären, dann könnte es vielleicht helfen, die Schnittstelle zu verbessern.
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
### 4.10 Debugging
### 4.10 Debugging
Eine Schnittstelle ist wie ein Vertrag zwischen der Funktion und den Aufrufenden. Die Aufrufenden stimmen zu, bestimmte Parameter bereitzustellen und die Funktion stimmt zu, eine bestimmte Aufgabe zu erledigen.
Eine Schnittstelle ist wie ein Vertrag zwischen der Funktion und den Aufrufenden. Die Aufrufenden stimmen zu, bestimmte Parameter bereitzustellen und die Funktion stimmt zu, eine bestimmte Aufgabe zu erledigen.
Beispielsweise benötigt die Funktion `polyline` vier Parameter:
Beispielsweise benötigt die Funktion `polyline` vier Parameter:
- `t` muss eine Schildkröte (Typ `Turtle`) sein,
- `t` muss eine Schildkröte (Typ `Turtle`) sein,
- `n` muss eine ganze Zahl sein,
- `n` muss eine ganze Zahl sein,
- `length` muss eine positive Zahl sein,
- `length` muss eine positive Zahl sein,
- `angle` muss eine Zahl sein, die einen Winkel in Grad darstellt.
- `angle` muss eine Zahl sein, die einen Winkel in Grad darstellt.
Diese Anforderungen nennen wir auch **Vorbedingungen**, denn es wird vorausgesetzt, dass sie erfüllt sind, bevor die Funktion ausgeführt wird. Umgekehrt heißen Bedingungen am Ende einer Funktion **Nachbedingungen**. Nachbedingungen schließen die beabsichtigte Wirkung der Funktion (wie z.B. ein Linienstück zeichnen) und etwaige Nebeneffekte (wie z.B. die Schildkröte zu bewegen oder andere Änderungen vorzunehmen) ein.
Diese Anforderungen nennen wir auch **Vorbedingungen**, denn es wird vorausgesetzt, dass sie erfüllt sind, bevor die Funktion ausgeführt wird. Umgekehrt heißen Bedingungen am Ende einer Funktion **Nachbedingungen**. Nachbedingungen schließen die beabsichtigte Wirkung der Funktion (wie z.B. ein Linienstück zeichnen) und etwaige Nebeneffekte (wie z.B. die Schildkröte zu bewegen oder andere Änderungen vorzunehmen) ein.
Die Erfüllung der Vorbedingungen ist die Aufgabe der Aufrufenden. Wenn die Aufrufenden eine (ordentlich dokumentierte!) Vorbedingung verletzen und die Funktion arbeitet nicht richtig, dann liegt der Fehler bei den Aufrufenden, nicht bei der Funktion.
Die Erfüllung der Vorbedingungen ist die Aufgabe der Aufrufenden. Wenn die Aufrufenden eine (ordentlich dokumentierte!) Vorbedingung verletzen und die Funktion arbeitet nicht richtig, dann liegt der Fehler bei den Aufrufenden, nicht bei der Funktion.
Wenn die Vorbedingungen erfüllt sind und die Nachbedingungen sind es nicht, dann liegt der Fehler bei der Funktion. Wenn ihre Vor- und Nachbedingungen klar und deutlich sind, dann kann das sehr beim Debugging helfen.
Wenn die Vorbedingungen erfüllt sind und die Nachbedingungen sind es nicht, dann liegt der Fehler bei der Funktion. Wenn ihre Vor- und Nachbedingungen klar und deutlich sind, dann kann das sehr beim Debugging helfen.
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
### 4.11 Glossar
### 4.11 Glossar
Legen wir uns eine Liste mit den wichtigsten Begriffen an, die wir im Kapitel 4 gelernt haben:
Legen wir uns eine Liste mit den wichtigsten Begriffen an, die wir im Kapitel 4 gelernt haben:
- Methode:
- Methode:
- Schleife: Eine Schleife ist eine Folge von Anweisungen, die mehrfach hintereinander ausgeführt werden.
- Schleife: Eine Schleife ist eine Folge von Anweisungen, die mehrfach hintereinander ausgeführt werden.
- Verkapselung:
- Verkapselung:
- Verallgemeinerung:
- Verallgemeinerung:
- Schlüsselwortargument:
- Schlüsselwortargument:
- Schnittstelle:
- Schnittstelle:
- Refactoring:
- Refactoring:
- Entwicklungsplan:
- Entwicklungsplan:
- Docstring:
- Docstring:
- Vorbedingung:
- Vorbedingung:
- Nachbedingung:
- Nachbedingung:
Ergänzen Sie die Liste in eigenen Worten. Das ist eine gute Erinnerungs- und Übungsmöglichkeit.
Ergänzen Sie die Liste in eigenen Worten. Das ist eine gute Erinnerungs- und Übungsmöglichkeit.
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
### 4.12 Übung
### 4.12 Übung
#### Aufgabe 1
#### Aufgabe 1
Laden Sie den Code für dieses Kapitel [hier](http://thinkpython2.com/code/polygon.py) herunter.
Laden Sie den Code für dieses Kapitel [hier](http://thinkpython2.com/code/polygon.py) herunter.
*Hinweis: Um Probleme mit Turtle+Jupyter zu vermeiden, stellen Sie sicher, dass am Ende Ihres Programmes stets die folgenden beiden Zeilen stehen:*
*Hinweis: Um Probleme mit Turtle+Jupyter zu vermeiden, stellen Sie sicher, dass am Ende Ihres Programmes stets die folgenden beiden Zeilen stehen:*
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
turtle.mainloop()
turtle.mainloop()
turtle.bye()
turtle.bye()
```
```
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
1. Zeichnen Sie (mit Stift und Papier) ein Stapeldiagramm (siehe [Kapitel 3](#3.9-Stapel-Diagramme)), welches den Zustand des Programms zeigt, während die Anweisung `circle(bob, radius)` ausgeführt wid. Sie können das manuell herausfinden, oder `print`-Anweisungen zum Code hinzufügen. (*Hinweis: Unter Umständen kann Ihnen [Python-Tutor](http://pythontutor.com/) dabei helfen*)
1. Zeichnen Sie (mit Stift und Papier) ein Stapeldiagramm (siehe [Kapitel 3](#3.9-Stapel-Diagramme)), welches den Zustand des Programms zeigt, während die Anweisung `circle(bob, radius)` ausgeführt wid. Sie können das manuell herausfinden, oder `print`-Anweisungen zum Code hinzufügen. (*Hinweis: Unter Umständen kann Ihnen [Python-Tutor](http://pythontutor.com/) dabei helfen*)
2. Die Version der Funktion `arc` in [Abschnitt 4.7](#4.7-Refactoring) ist nicht besonders präzise, denn die lineare Näherung eines Kreises ist immer ausserhalb des wahren Kreises. Daher steht die Schildkröte am Ende immer ein paar Pixel vom richtigen Ziel entfernt. Die Lösung im Python-Code zeigt eine Möglichkeit, die Auswirkung dieses Fehlers zu reduzieren. Lesen Sie sich den Code durch und schauen Sie, ob das für Sie einen Sinn ergibt. Vielleicht hilft es Ihnen weiter, ein Diagramm zu zeichnen.
2. Die Version der Funktion `arc` in [Abschnitt 4.7](#4.7-Refactoring) ist nicht besonders präzise, denn die lineare Näherung eines Kreises ist immer ausserhalb des wahren Kreises. Daher steht die Schildkröte am Ende immer ein paar Pixel vom richtigen Ziel entfernt. Die Lösung im Python-Code zeigt eine Möglichkeit, die Auswirkung dieses Fehlers zu reduzieren. Lesen Sie sich den Code durch und schauen Sie, ob das für Sie einen Sinn ergibt. Vielleicht hilft es Ihnen weiter, ein Diagramm zu zeichnen.
2. Überlegen Sie erst, wie man ein einzelnes Blütenblatt zeichnen kann.
2. Überlegen Sie erst, wie man ein einzelnes Blütenblatt zeichnen kann.
3. Welche Informationen müssen der Funktion in der Schnittstelle übergeben werden?
3. Welche Informationen müssen der Funktion in der Schnittstelle übergeben werden?
4. Die Funktion braucht eine Schildkröte, die Größe des Blütenblatts und Winkel in dem das Blütenblatt gezeichnet werden soll (also wie breit das Blütenblatt sein soll)
4. Die Funktion braucht eine Schildkröte, die Größe des Blütenblatts und Winkel in dem das Blütenblatt gezeichnet werden soll (also wie breit das Blütenblatt sein soll)
3. Jedes Blütenblatt besteht aus 2 Kreisbögen, also brauchen Sie arc (nutzen Sie ihre eigene Funktion oder kopieren Sie arc aus polygon.py)
3. Jedes Blütenblatt besteht aus 2 Kreisbögen, also brauchen Sie arc (nutzen Sie ihre eigene Funktion oder kopieren Sie arc aus polygon.py)
4. Nach dem ersten Kreisbogen muss die Schildkröte sich soweit drehen, dass sie mit dem nächsten Kreisbogen eine volle 180° Drehung vollzogen hat
4. Nach dem ersten Kreisbogen muss die Schildkröte sich soweit drehen, dass sie mit dem nächsten Kreisbogen eine volle 180° Drehung vollzogen hat
5. Wie können sie die Blütenblätter dann miteinander zu einer blume verbinden?
5. Wie können sie die Blütenblätter dann miteinander zu einer blume verbinden?
8. Was muss der Funktion Blume in der Schnittstelle an Argumenten übergeben werden?
8. Was muss der Funktion Blume in der Schnittstelle an Argumenten übergeben werden?
9. Sie brauchen alle Argumente, die in der Funktion an Blatt übergeben werden und natürlich auch die Anzahl n an Blütenblättern, aus denen die Blume bestehen soll.
9. Sie brauchen alle Argumente, die in der Funktion an Blatt übergeben werden und natürlich auch die Anzahl n an Blütenblättern, aus denen die Blume bestehen soll.
6. In Blume muss Blatt n mal aufgerufen werden
6. In Blume muss Blatt n mal aufgerufen werden
6. Um die Blütenblätter gleichmäßig um den Mittelpunkt der Blume zu verteilen, muss der Winkel zwischen den Blättern so berechnet werden, dass nach Vollenden der Blume eine 360° Wendung vollzogen wurde.
6. Um die Blütenblätter gleichmäßig um den Mittelpunkt der Blume zu verteilen, muss der Winkel zwischen den Blättern so berechnet werden, dass nach Vollenden der Blume eine 360° Wendung vollzogen wurde.
7. Dafür muss der Winkel zwischen den Blättern 360/n betragen
7. Dafür muss der Winkel zwischen den Blättern 360/n betragen
Hier ist eine mögliche [Lösung](http://thinkpython2.com/code/flower.py)
Hier ist eine mögliche [Lösung](http://thinkpython2.com/code/flower.py)
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
import math
import math
import turtle
import turtle
bob=turtle.Turtle()
bob=turtle.Turtle()
# Damit diese Lösung funktioniert müssen def arc und def polyline bekannt sein.
# Damit diese Lösung funktioniert müssen die Funktionen arc und polyline schon definiert worden sein.
1. Wir gehen analog zu Blume vor, und zeichnen die einzelnen "Kuchenstücke" bevor wir sie zu dem "Kuchen" zusammensetzen.
1. Wir gehen analog zu Blume vor, und zeichnen die einzelnen "Kuchenstücke" bevor wir sie zu dem "Kuchen" zusammensetzen.
2. Wir müssen die obere Seitenlänge berechnen um sie zeichnen zu können. Sinus verwendet Bogenmaß, das heißt um die "richtige" Seitenlänge zu erhalten müssen wir den Winkel umrechnen. *Hinweiß: Dafür wird mit $\pi/180$ multipliziert*
2. Wir müssen die obere Seitenlänge berechnen um sie zeichnen zu können. Sinus verwendet Bogenmaß, das heißt um die "richtige" Seitenlänge zu erhalten müssen wir den Winkel umrechnen. *Hinweiß: Dafür wird mit $\pi/180$ multipliziert*
3. Die vollständige Formel ist $2*r*sin(angle*\pi/180)$
3. Die vollständige Formel ist $2*r*sin(angle*\pi/180)$
4. Über die 3 Seiten verteilt, muss sich die Schildkröte soweit drehen, dass sie wieder am Ausgangspunkt ankommen.
4. Über die 3 Seiten verteilt, muss sich die Schildkröte soweit drehen, dass sie wieder am Ausgangspunkt ankommen.
5. Sie muss zweimal die Strecke r laufen und dazwischen einmal die Strecke, die wir berechnet haben.
5. Sie muss zweimal die Strecke r laufen und dazwischen einmal die Strecke, die wir berechnet haben.
6. Dazwischen muss sich die Schildkröte immer drehen. Verwenden Sie dafür angle und Vielfältige von 90 und probieren Sie verschiedene Varienten aus, bis es funktioniert.
6. Dazwischen muss sich die Schildkröte immer drehen. Verwenden Sie dafür angle und Vielfältige von 90 und probieren Sie verschiedene Varienten aus, bis es funktioniert.
7. Damit kuchen später funktioniert, muss die Schildkröte wieder ihre Ausgangsposition Annehmen. Dafür fügen Sie noch je eine Drehung am Anfang und am Ende ein.
7. Damit kuchen später funktioniert, muss die Schildkröte wieder ihre Ausgangsposition Annehmen. Dafür fügen Sie noch je eine Drehung am Anfang und am Ende ein.
8. Für kuchen können Sie blume wiederverwenden, müssen allerdings einige Veränderungen vornehmen. Damit keine Lücken entstehen, muss die Funktion angle berechnen, statt diesen Wert übergehen zu bekommen. Dann muss auch der Winkel für Stück angepasst werden.
8. Für kuchen können Sie blume wiederverwenden, müssen allerdings einige Veränderungen vornehmen. Damit keine Lücken entstehen, muss die Funktion angle berechnen, statt diesen Wert übergehen zu bekommen. Dann muss auch der Winkel für Stück angepasst werden.
9. Um die Stücke zu verbinden wird in der for Schleife eine Drehung von 360/n vorgenommen. Die Drehung in Stück muss dann halb so groß sein.
9. Um die Stücke zu verbinden wird in der for Schleife eine Drehung von 360/n vorgenommen. Die Drehung in Stück muss dann halb so groß sein.
*(Hier ist eine mögliche [Lösung](http://thinkpython2.com/code/pie.py))*
*(Hier ist eine mögliche [Lösung](http://thinkpython2.com/code/pie.py))*
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
import math
import math
import turtle
import turtle
# Arbeiten Sie diese Lösung durch und kommentieren Sie die einzelnen Schritte
def stück (t,r, angle):
def stück (t,r, angle):
c=2*r*(math.sin(angle*math.pi/180))
c=2*r*(math.sin(angle*math.pi/180))
t.rt(angle)
t.rt(angle)
t.fd(r)
t.fd(r)
t.lt(90+angle)
t.lt(90+angle)
t.fd(c)
t.fd(c)
t.lt(90+angle)
t.lt(90+angle)
t.fd(r)
t.fd(r)
t.lt(180-angle)
t.lt(180-angle)
def kuchen (t, n, r):
def kuchen (t, n, r):
angle=360/n
angle=360/n
for i in range (n):
for i in range (n):
stück(t,r,angle/2)
stück(t,r,angle/2)
t.lt(angle)
t.lt(angle)
turtle.mainloop()
turtle.mainloop()
turtle.bye()
turtle.bye()
bob=turtle.Turtle()
bob=turtle.Turtle()
kuchen(bob,4,40,40)
kuchen(bob, 5, 100)
turtle.mainloop()
turtle.bye()
```
```
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
#### Aufgabe 4
#### Aufgabe 4
Lesen Sie etwas zu Spiralen auf [Wikipedia](https://de.wikipedia.org/wiki/Spirale). Schreiben Sie dann ein Programm, welches eine [Archimedische Spirale](https://de.wikipedia.org/wiki/Archimedische_Spirale) (oder eine andere) zeichnet.
Lesen Sie etwas zu Spiralen auf [Wikipedia](https://de.wikipedia.org/wiki/Spirale). Schreiben Sie dann ein Programm, welches eine [Archimedische Spirale](https://de.wikipedia.org/wiki/Archimedische_Spirale) (oder eine andere) zeichnet.
1. Sie müssen sich entscheiden, welche Argumente Sie in der Schnittstelle übergeben wollen und welche Sie der Funktion übergeben wollen. (Hier habe ich mich entschieden, Nutzern verschiedene funktionierende Schleifen zur Auswahl zu geben)
1. Sie müssen sich entscheiden, welche Argumente Sie in der Schnittstelle übergeben wollen und welche Sie der Funktion übergeben wollen. (Hier habe ich mich entschieden, Nutzern verschiedene funktionierende Schleifen zur Auswahl zu geben)
2. In einem minimalistischen Schnittstellen Entwurf muss noch mindestens die Schildkröte an die Funktion übergeben werden.
2. In einem minimalistischen Schnittstellen Entwurf muss noch mindestens die Schildkröte an die Funktion übergeben werden.
3. Die Formel für die Berechnung von Spiralen ist $r = a + b\theta$ , a können Sie auf 0.1 und b auf 0.0002 als Ausgangswerte festlegen.
3. Die Formel für die Berechnung von Spiralen ist $r = a + b\theta$ , a können Sie auf 0.1 und b auf 0.0002 als Ausgangswerte festlegen.
4. Andere Parameterm die Sie entweder in der Schnittstelle oder in der Funktion festlegen müssen sind der Winkel theta, die Anzahl an Spiralensegmenten und die Länge der einzelnen Segmente.
4. Andere Parameterm die Sie entweder in der Schnittstelle oder in der Funktion festlegen müssen sind der Winkel theta, die Anzahl an Spiralensegmenten und die Länge der einzelnen Segmente.
5. Analog zum Kreisbogen wird auch die Spirale durch kurze gerade Segmente und Drehungen gezeichnet. Da das Zeichnen von Segmenten n-mal wiederholt wird, benötigen Sie eine for-Schleife.
5. Analog zum Kreisbogen wird auch die Spirale durch kurze gerade Segmente und Drehungen gezeichnet. Da das Zeichnen von Segmenten n-mal wiederholt wird, benötigen Sie eine for-Schleife.
6. In der Schleife muss für jedes Segment neu berechnet werden wie weit die Schildkröte sich drehen muss, da der Winkel nicht konstant bleibt. Dafür verwendet die Lösung: dtheta = 1 / (a + b * theta)
6. In der Schleife muss für jedes Segment neu berechnet werden wie weit die Schildkröte sich drehen muss, da der Winkel nicht konstant bleibt. Dafür verwendet die Lösung: dtheta = 1 / (a + b * theta)
7. Da diese Formel theta als den Winkel des vorherigen Abschnitts verwendet, muss theta ebenfalls in jedem Schleifendurchlauf überschrieben werden - also addieren Sie dtheta auf theta auf.
7. Da diese Formel theta als den Winkel des vorherigen Abschnitts verwendet, muss theta ebenfalls in jedem Schleifendurchlauf überschrieben werden - also addieren Sie dtheta auf theta auf.
Eine [Lösung](http://thinkpython2.com/code/spiral.py)
Eine [Lösung](http://thinkpython2.com/code/spiral.py)
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
def spirale(t,n):
def spirale(t,n):
'''In dieser Spirale bestimmt der Nutzer, wie viele Segmente gezeichnet werden, die Windung der Spirale ist
'''In dieser Spirale bestimmt der Nutzer, wie viele Segmente gezeichnet werden, die Windung der Spirale ist
in der Funktion festgelegt.
in der Funktion festgelegt.
'''
'''
length=3
length=3
a=0.1
a=0.1
b=0.0002
b=0.0002
theta=0.0
theta=0.0
for i in range (n):
for i in range (n):
t.fd(length)
t.fd(length)
dtheta = 1 / (a + b * theta)
dtheta = 1 / (a + b * theta)
t.lt(dtheta)
t.lt(dtheta)
theta = theta + dtheta
theta = theta + dtheta
import turtle
import turtle
bob=turtle.Turtle()
bob=turtle.Turtle()
spirale(bob,1000)
spirale(bob,1000)
turtle.mainloop()
turtle.mainloop()
turtle.bye()
turtle.bye()
```
```
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
#### Aufgabe 5
#### Aufgabe 5
*(Hinweis: Dies ist eher eine Fleiß- und Zusatzaufgabe.)*
*(Hinweis: Dies ist eher eine Fleiß- und Zusatzaufgabe.)*
Die Buchstaben des Alphabets sind aus ein paar grundlegenden Elementen zusammengesetzt wie z.B. vertikalen und horizontalen Linien und einigen Kurven. Entwerfen Sie ein Alphabet, welches mit einer kleinen Anzahl einfacher Elemente gezeichnet werden kann und schreiben Sie dann Funktionen zum Zeichnen der Buchstaben.
Die Buchstaben des Alphabets sind aus ein paar grundlegenden Elementen zusammengesetzt wie z.B. vertikalen und horizontalen Linien und einigen Kurven. Entwerfen Sie ein Alphabet, welches mit einer kleinen Anzahl einfacher Elemente gezeichnet werden kann und schreiben Sie dann Funktionen zum Zeichnen der Buchstaben.
Sie sollten eine Funktion für jeden Buchstaben schreiben, die Sie `draw_a`, `draw_b`, etc. nennen und diese Funktionen in eine Datei namens `letters.py` packen. Sie können [hier](http://thinkpython2.com/code/typewriter.py) eine "Schildkrötenschreibmaschine" herunterladen und damit ihren Code testen.
Sie sollten eine Funktion für jeden Buchstaben schreiben, die Sie `draw_a`, `draw_b`, etc. nennen und diese Funktionen in eine Datei namens `letters.py` packen. Sie können [hier](http://thinkpython2.com/code/typewriter.py) eine "Schildkrötenschreibmaschine" herunterladen und damit ihren Code testen.
Sie finden eine Lösung für diese Aufgabe [hier](http://thinkpython2.com/code/letters.py); Diese benötigt auch [polygon.py](http://thinkpython2.com/code/polygon.py).
Sie finden eine Lösung für diese Aufgabe [hier](http://thinkpython2.com/code/letters.py); Diese benötigt auch [polygon.py](http://thinkpython2.com/code/polygon.py).
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
 Speichern Sie dieses Notebook, so dass Ihre Änderungen nicht verlorengehen (nicht auf einem Pool-Rechner). Klicken Sie dazu oben links auf das Disketten-Icon und nutzen Sie beispielsweise einen USB-Stick, E-Mail, Google Drive, Dropbox oder Ihre [HU-Box](https://box.hu-berlin.de/).
 Speichern Sie dieses Notebook, so dass Ihre Änderungen nicht verlorengehen (nicht auf einem Pool-Rechner). Klicken Sie dazu oben links auf das Disketten-Icon und nutzen Sie beispielsweise einen USB-Stick, E-Mail, Google Drive, Dropbox oder Ihre [HU-Box](https://box.hu-berlin.de/).