Tipps, Tricks und Aufgaben

Block 8

Tipps und Tricks

for in Listen

Du kannst for-Schlaufen auch verwenden um Listen zu definieren. Python hat dafür eine praktische Syntax, die zu beginn etwas rückwärts aussieht.

start_values = [[1,2,3,4],[7,6,5],[9,8,0]] maximas = [max(l) for l in start_values] print(maximas)

Diese Schreibweise ist auch praktisch wenn du mit range() Listen erstellen möchtest

l = [v**2 for v in range(10)]

Dictionaries

Bisher haben wir mit Listen, Arrays und Strings drei Elemente iterierbare Typen kennengelernt. Ein weiterer praktischer Datentyp von Python sind Dictionaries. Dictionaries funktionieren ähnlich wie Listen. Die Einträge werden aber nicht einfach nummeriert. Stattdessen kannst du für jeden Eintrag einen Schlüssel festlegen.

ich = { 'name' : 'Nicola', 'start' : 2003 } print(ich['name']) print(ich['start'])

Auch ein Dict-Objekt hat verschiedene Methoden. Besonders die beiden Methoden keys() und values() wirst du wohl häufig gebrauchen.

fakultaet = { 1 : 1, 2: 2, 3: 6, 4: 24, 5: 120 } sum = 0 for f in fakultaet.values(): sum += f print(sum)

Rekursive Funktionen

Rekursive Funktionen sind Funktion, die sich selbst wieder aufrufen. Sie beziehen sich also auf sich selbst.

def rekurs(tiefe): print(tiefe) if tiefe > 0: rekurs(tiefe-1) rekurs(10)

Das Beispiel oben hätten wir auch mit einer einfachen Schlaufe erledigen können. Rekursive Funktionen sind vor allem dann nützlich, wenn sie für mehrere Unterargumente aufgerufen werden. Das Folgende Beispiel halbiert eine Strecke immer wieder, bis die gewünschte Tiefe erreicht ist.

from pylab import * def halbieren(min_val, max_val, tiefe): mitte = (max_val-min_val)/2. + min_val plot([mitte], [tiefe], 'b+') if tiefe > 0: halbieren(min_val, mitte, tiefe-1) halbieren(mitte, max_val, tiefe-1) min_val = 0 max_val = 16 tiefe = 3 plot([min_val, max_val], [tiefe,tiefe], 'r') halbieren(0, 16, tiefe) axis([min_val-1, max_val+1, -1, tiefe+1]) show()

Rekursive Funktionen können hier eine sehr elegante Lösung bieten. Ihr grösster Nachteil ist, dass rasch sehr viele Funktionsaufrufe verursachen. Das kann zu sehr langsamen Programmen führen.

random

Mit Zufallszahlen kannst du viele unterhaltsame Programm schreiben und auch für ernstere Aufgaben sind Zufallszahlen oft wichtig. Sowohl Standard-Python, wie auch NumPy bieten ein random-Modul.

Hinweis: Du darfst die Datei für dieses Beispiel nicht random.py nennen. Sonst nimmt Python beim import-Befehl deine Datei statt das random-Modul.

# Standard-Python import random wurf = 0 while wurf != 6: wurf = random.randint(1,6) print(wurf) gauss = [random.gauss(2, 0.5) for _ in range(20)] print(gauss) # und das gleiche mit pylab from pylab import * wurf = 0 while wurf != 6: wurf = randint(1,7) print(wurf) gauss = normal(2, 0.5, 20) print(gauss)

Wie gewohnt hilft dir die interne Hilfe von Python weiter, falls du mehr über die random-Module wissen möchtest.

doctest

Oft ist ein Beispiel die beste Art von Dokumentation. Doch das stimmt nur, wenn das Beispiel auch wirklich funktioniert. Python kann Beispiele in der Dokumentation automatisch testen. Damit das klappt, musst du dich aber an die Konvention halten. Glücklicherweise ist die Konvention sehr natürlich.

def calc_sum(a,b): """calculates the sum of two values takes two numbers and returns the sum of them Parameters ---------- a : any number first summand b : any number second summand Returns ------- a+b : same type as input the summ of the input Examples -------- >>> calc_sum(21,21) 42 >>> calc_sum(44.4,-2.4) 42.0 >>> calc_sum(2j,3) (3+2j) """ return a+b

Kopiere diese komplexe Funktion in eine Datei doctest-example.py.

Tipp: Mit [ctrl]+[u] kannst du dir den HTML-Source anzeigen lassen. Wenn du von dort kopierst, bleiben auch die Zeilenumbrüche erhalten.

In der Shell kannst du doctest dann mit folgendem Befehl starten.

python3 -m doctest -v doctest-example.py

Mit -m doctest teilst du Python mit, dass doctest ausgeführt werden soll. -v lässt doctest mehr Output ausgeben, so dass du siehst was passiert. Ohne -v würde doctest nur etwas ausgeben, falls ein Beispiel nicht funktioniert. Passe eines der Beispiel so an, dass es nicht mehr stimmt und schaue was passiert.

Aufgaben

Im folgenden findest du verschiedene, komplexere Aufgaben. Du musst jetzt nicht jede Aufgabe lösen. Wähle die spannendste(n) Aufgaben und bearbeite diese. Du kannst auch später noch hierher zurückkehren.

Überlege dir bei jeder Aufgabe zuerst, was du genau machen musst. Spiele allfällige Algorithmen zuerst von Hand durch und achte dabei darauf, welche Schritte sich wiederholen. Skizziere anschliessend auf Papier eine Programmstruktur sowie allfällig nötige Funktionen. Diskutiere deine Ideen mit anderen. (Ihr dürft diese Aufgaben auch gerne zu zweit lösen. Bei der Gelegenheit könnt ihr gleich die Verwendung von git üben.)

Kopfrechen-Trainer

Verwende eines der random-Module um ein Programm zu schreiben, das dir hilft dein Kopfrechnen zu trainieren. Das Programm soll Zufallszahlen zu einfachen Rechnungen kombinieren, die du dann lösen musst. Überlege dir dabei auch, wo Probleme entstehen können und wie du diese verhindern kannst.

Sobald du ein funktionierendes Grundprogramm hast, kannst du dieses auch mit eigenen Ideen erweitern.

Chaos-Spiel

Implementiere ein Programm für folgenden Algorithmus

Lass dein Programm dann für ein paar 1000 Schritte laufen.

Primfaktoren

Schreib ein Programm, das eine Zahl startwert einliest und ihre Primfaktoren bestimmt. Verwende dabei folgenden Algorithmus

Fibonacci-Zahlen

Definiere zwei Funktionen die jeweils die n-te Fibonacci Zahl berechnen. Mache das einmal mittels Rekursion und einmal mittels while- oder for-Schlaufe. Verwende dann %timeit um herauszufinden wie schnell die beiden Funktionen sind.

Einen analogen Vergleich kannst du auch mit verschiedenen Implementation für die Fakultät durchführen. Weshalb ist der Effekt bei der Fakultät kleiner? Was passiert wenn du die Fakultät mittels Listen oder Arrays berechnest?

Koch-Kurve

Beispiele der Koch-Kurve

In dieser Aufgabe soll ein Programm geschrieben werden, das Graphiken wie die oben gezeigten erzeugt. Dies kannst du rekursive lösen. Dazu übergibst du der rekursiven Funktion die Endpunkte einer Linie. Die Funktion zeichnet dann entweder diese Linie oder berechnet die Abschnitte deiner Figur und ruft sich selbst für jeden Abschnitt neu auf. So ersetzt du jeweils jedes Linienstück durch die Figur selbst.

Figuren, welche nach diesem Muster gebildet werden, nennt man Koch-Kurven. Sie sind nach dem schwedischen Mathematiker Helge von Koch benannt. Er beschäftigte sich um die Jahrhundertwende des 19. und 20. Jahrhunderts, mit solchen Figuren.

Schreibe ein Programm das die Iterationstiefe einliest und zu dieser eine Koch-Kurve auf den Bildschirm zeichnet. Da sich die Orientierung deiner Linie laufen ändert, lohnt es sich diese Aufgabe mit Vektorrechnung zu lösen. Definiere die dafür nötigen Funktionen in einem separaten Modul.

Speziell elegant ist es, wenn du in deinem Programm auch die Grundform ohne viel Aufwand anpassen kannst.

Mit axis('equal') bzw. mit ax.set_aspect('equal' kannst du dafür sorgen, dass beide Achsen die gleiche Skalierung verwenden. Dann werden deine gleichseitigen Dreiecke auch wirklich als gleichseitige Dreiecke dargestellt.