~~NOTOC~~ ====== Funktionen ====== ... oder: Wie man grössere Programme übersichtlich gestaltet. (teilweise Vorschau auf die Videos) Das Aufteilen eines grösseren Vorhabens in Teilvorhaben, die sogenannten **Module**, nennt man **Modularisierung**, auch **modularen Entwurf** oder **Baukastenprinzip**. Dadurch ist es leichter, die Übersicht über das gesamte Vorhaben zu behalten. Beispiel: Beim Bau eines Hauses übernehmen verschiedene Handwerker als Spezialisten diverse Aufgaben. In der Informatik wird dies oft durch **Funktionen** bewerkstelligt. Funktionen sind "Miniprogramme" oder "Unterprogramme" und erledigen eine gewisse Teilaufgabe (sie sind die "Spezialisten"). Wir haben schon viele Funktionen kennengelernt und verwendet, z. B. ''print'', ''input'', ''forward'', ''right'', ''penup'', ''setcolor'', ''random.random''. Funktionen werden aufgerufen (**Funktionsaufruf**), indem man den jeweiligen Funktionsnamen angibt und danach in runden Klammern die benötigten **Argumente** (= Übergabewerte) angibt (manchmal wird auch gar kein Argument benötigt). Als Argumente sind integers, strings, Booleans etc. erlaubt. **Die runden Klammern sind beim Funktionsaufreu stets hinzuschreiben, auch wenn keine Argumente übergeben werden.** Beispiele: * ''pencolor("red")'' ist ein Aufruf der Funktion ''pencolor'' mit ''"red"'' als Argument. * ''penup()'' ist ein Aufruf der Funktion ''penup''; diese Funktion nimmt keine Argumente entgegen. Funktionen haben einerseits den Zweck, sonst mehrfach auftauchenden Code zu bündeln; andererseits erlauben sie es, Programme sinnvoll zu strukturieren und so lesbarer zu machen (vgl. die Videos). Nun wirst du lernen, wie du selbst Funktionen definieren kannst! ===== Funktionen ohne Rückgabewert definieren (teils mit Turtle-Grafik) ===== Schau dir das folgende Video zu Funktionen an und löse die darin enthaltenen drei Aufgaben! [[https://fginfo.ksbg.ch/~olaf/videos-glf22/funktionen-ohne-rueckgabewert-teils-mit-turtle.mp4|Video "Funktionen mit Parametern selbst definieren (teils mit Turtle)"]] ---- Endzustand der Programme aus dem Video (mit kleinen sprachlichen Verbesserungen): def begruessung(): print("Hallo!") print("Ich bin eine Funktion.") def saluto(s): print("Buongiorno " + s + "!") def salutation(name, sprache): if sprache == 1: print("Bonjour " + name + " !") else: print("Buongiorno " + name + "!") begruessung() saluto("Pinocchio") saluto("Papagena") salutation("Pinocchio", 2) salutation("Jacques", 1) from turtle import * def dreieck(): for index in range(3): forward(100) left(120) def triangolo(a): for index in range(3): forward(a) left(120) def vieleck(a, n): for index in range(n): forward(a) left(360/n) dreieck() triangolo(123) triangolo(200) vieleck(77, 5) vieleck(27, 11) exitonclick() ===== Funktionen mit Rückgabewert definieren ===== Schau dir das folgende Video zu Funktionen an und löse die darin enthaltenen Aufgaben! [[https://fginfo.ksbg.ch/~olaf/videos-glf22/funktionen-mit-rueckgabewert.mp4|Video "Funktionen mit Rückgabewert"]] def f(x): return x ** 2 + 42 * x - 7 def zweihoch(n): return 2 ** n def ist_teiler_von(t, z): return z % t == 0 def hoch(basis, exponent): return basis ** exponent def summe_zweierpotenzen(n): summe = 0 for index in range(n + 1): summe = summe + zweihoch(index) return summe def summe_quadratzahlen(n): summe = 0 for index in range(n + 1): summe = summe + index ** 2 return summe print(summe_quadratzahlen(5)) print(summe_zweierpotenzen(4)) print(hoch(3, 6)) print(hoch(2, 10)) print(ist_teiler_von(7, 42)) print(ist_teiler_von(5, 42)) print(ist_teiler_von(13, 91)) print(f(2)) print(f(11)) print(zweihoch(10)) print(zweihoch(8)) ===== Definition von Funktionen (wurde in den Videos bereits erklärt) ===== Eine Funktionsdefinition sieht in Python wie folgt aus: def (): # Hier steht, # um vier Leerschläge eingerückt, # was die Funktion tut. # # Falls ein Rückgabewert zurückgegeben werden soll: return In Worten: * Die Funktionsdefinition wird mit einer Kopfzeile eingeleitet: * Sie beginnt mit dem Schlüsselwort ''def'' (für //define//). * Danach kommt der Name der Funktion, der im Wesentlichen frei gewählt werden kann. * Danach kommt ein Paar von Klammern, zwischen denen nichts steht oder ein Parameter (Name frei wählbar) oder mehrere durch Kommas getrennte Parameter. * Danach kommt ein Doppelpunkt '':''. * Nun folgt in den nächsten Zeilen **eingerückt** der eigentliche Code der Funktion ("body of the function"). * Optional, wenn ein Rückgabewert zurückgeliefert werden soll((so, wie man das erwartet, wenn man an den Funktionsbegriff in der Mathematik denkt)): Verwende das Schlüsselwort ''return'' und schreibe dahinter den Ausdruck für den Rückgabewert. Die Syntax ist also ähnlich wie bei ''for''- oder ''while''-Schleifen und ''if''-Statments: Eine Art Kopfzeile mit Doppelpunkt am Ende, danach eingerückt der eigentliche Code: Dieser wird bei jedem Funktionsaufruf ausgeführt. ===== Aufgaben ===== ==== Aufgabe: Liste der ersten Primzahlen; Funktion mit Rückgabewert ==== Öffne eine neues Python-Programm. (1) Schreibe eine Funktion((Eigentlich heisst die Funktion nur ''ist_prim'' (und nicht ''ist_prim(x)'').)) ''ist_prim(x)'', die entscheidet, ob der Parameter''x'' eine Primzahl ist, und dementsprechend ''True'' oder ''False'' zurückgibt. Initialisiere am Anfang der Funktionsdefinition eine (Hilfs-)Variable ''teiler_gefunden = False''. Gehe dann alle möglichen Teiler von ''x'' durch und setze diese Hilfsvariable auf ''True'', sobald du einen Teiler von ''x'' gefunden hast. (Denke an das "Divisionszeichen" ''%'', mit dessen Hilfe man leicht herausfindet, ob eine Zahl eine andere teilt.) ---- (2) Nutze deine Funktion ''ist_prim'', um eine Liste aller Primzahlen bis ''n = 10000'' auszugeben. Hinweis: Damit nicht jede Primzahl in einer neuen Zeile steht: Der Befehl ''print(p, end = ", ")'' gibt den Wert der Variablen ''p'' aus, danach ein Komma gefolgt von einem Leerschlag, und geht danach //nicht// in die nächste Zeile. Bemerkung: Diese Methode, eine Liste von Primzahlen, ist nicht besonders effizient. Schneller geht es etwa mit dem Sieb des Eratosthenes. ==== Aufgabe: Mäander (Ornamentik); Funktion ohne Rückgabewert==== Ziel der Aufgabe ist, den kreisförmigen Mäander effizient zu zeichnen. {{:lehrkraefte:snr:informatik:glf22:python:ornament-kreis.png?nolink&400|}} Da die rote Figur mehrfach vorkommt, ist es sinnvoll, diese Figur von einer Funktion zeichnen zu lassen. * (1) Definiere eine Funktion ''ornament(a)'': Sie soll den roten Streckenzug zeichnen, wobei das "kürzeste" Teilstück ''a'' Pixel lang ist. Die beiden anderen Teilstücke sind dann ''2 * a'' und ''3 * a'' Pixel lang. Der Streckenzug soll links oben beginnend gezeichnet werden mit Blickrichtung der Turtle nach rechts; am Ende soll sie wieder nach rechts schauen). Hinweis: Die Bilder wurden mit ''a = 20'' erzeugt. * (2) Verwende deine Funktion und eine for-Schleife, um den folgenden Mäander zu zeichnen (alles soll einfarbig sein). Passe die Stiftdicke geeignet an. {{:lehrkraefte:snr:informatik:glf22:python:ornament-gerade.png?nolink&400|}} * (3) Ändere dein Programm so, dass der obige kreisförmige Mäander entsteht, der aus ''n = 23'' Einzelmustern besteht (wieder alles einfarbig). Zum anfänglichen Positionieren der Turtle könnte die [[lehrkraefte:snr:informatik:glf22:python:funktionen#direktes_positionieren_der_turtle|folgende Infobox]] nützlich sein. Zeichne den folgenden rechteckigen Mänder mit Hilfe einer zusätzlichen Funktion ''eckbewegung()'', die den orangen Teil des Musters zeichnet und viermal aufgerufen wird. {{:lehrkraefte:snr:informatik:glf22:python:ornament-rechteck.png?nolink&300|}} Zeichne ähnliche Muster! Zur Inspiration: * [[https://de.wikipedia.org/wiki/M%C3%A4ander_(Ornamentik)|Wikipedia: Mäander (Ornamentik)]] * [[https://de.wikipedia.org/wiki/Fries|Wikipedia: Fries]] * [[https://de.wikipedia.org/wiki/Ornament|Wikipedia: Ornament]] ===== Direktes Positionieren der Turtle ===== Die wichtigsten Zustandsparameter der Turtle sind ihre Position und ihre Blickrichtung (weniger wichtig sind Farbe und Stiftdicke etc.). * Ihre Position wird durch $x$- und $y$-Koordinate angegeben. * Ihre Blickrichtung wird durch einen Winkel in Grad angegeben: $0^\circ$: nach rechts; $90^\circ$: nach oben, $180^\circ$: nach links etc. Das zugrunde liegende Koordinatensystem liegt zentriert im Standard-Turtle-Fenster: Sichtbar sind alle Punkte mit * x-Koordinaten zwischen -473 und +473 und * y-Koordinaten zwischen -398 und +398. ((jedenfalls auf meinem Laptop; wenn ich die Dokumentation richtig verstehe, nimmt das Standard-Turtle-Fenster 50 % der Bildschirmbreite und 75 % der Bildschirmhöhe ein)) Man kann die Turtle direkt in einen gewissen Zustand versetzen: * ''setposition(-100, 50)'' bewegt die Turtle auf den Punkt $(-100, 50)$. (Kürzer hat ''setpos(-100, 50)'' denselben Effekt.) * ''setheading(45)'' dreht man die Turtle so, dass ihre Blickrichtung zur positiven $x$-Achse einen Winkel von $45^\circ$ bildet bildet (in mathematisch positivem Drehsinn, also dem Gegenuhrzeigersinn), die Turtle schaut also nach rechts oben. (Kürzer hat ''seth(45)'' denselben Effekt.) * ''home()'' bewegt die Turtle in die Start-Position. ===== W3Schools-Material zu Funktionen ===== Alles vor dem roten Kasten sollte bekannt sein auf der Seite https://www.w3schools.com/python/python_functions.asp. Exercises dazu (die ersten vier Fragen solltest du beantworten können): https://www.w3schools.com/python/exercise.asp?filename=exercise_functions1 ===== Weitere Bemerkungen zu Funktionen (einiges wurde bereits in den Videos erklärt) ===== Zum besseren Verständnis ist es sinnvoll, Funktionen in vier Arten einzuteilen, je nachdem, ob sie * **Parameter** besitzen oder nicht (also **Argumente** beim Funktionsaufruf angegeben werden müssen oder nicht); * einen **Rückgabewert** zurückgeben oder nicht. In der folgenden Tabelle ist für jeder dieser vier Arten ein Beispiel angegeben und darunter ein Aufruf der Funktion. |Funktionen ^ ohne Parameter ^ mit Parameter(n) ^ ^ ohne Rückgabewert | ''penup'' | ''pensize'' | ^ | ''penup()'' | ''pensize(10)'' | ^ mit Rückgabewert | ''random.random'' | ''input'' | ^ | ''random.random()'' | ''input("Wie heisst du?")'' | Grob gesagt kann man Aufrufe und Definitionen von Funktionen daran erkennen, dass nach ihnen ein Paar runder Klammern (mit oder ohne Argumente bzw. Parameter dazwischen) auftaucht! Beachte: Sogenannte **Schlüsselworte** wie ''if'', ''else'', ''for'', ''while'', ''def'' etc. sind keine Funktionen. Sie werden verwendet, um den Ablauf von Python-Programmen zu steuern. Bisher nicht in diesem Kurs erklärt: Variablen haben in Python **Geltungsbereiche**, vgl. https://www.w3schools.com/python/python_scope.asp. Dies erlaubt, denselben Variablennamen mehrfach zu verwenden (etwa eine Variable namens ''x'' im "Hauptprogramm" und eine Variable (oder einen Parameter) namens ''x'' in einer Funktion), ohne dass dies zu Konfliken führt. Wenn man als Programmieranfänger auf Nummer sicher gehen will, verwende man jeden Variablennamen nur einmal. ===== Bonus-Aufgabe: Funktionen zum Zeichnen einer Spirale und zum "unsichtbaren" Bewegen der Turtle ===== {{:lehrkraefte:snr:informatik:glf22:python:vier-spiralen.png?300|}} Ergänze das folgende Programm um die Definition zweier Funktionen (um so das obige Bild zu zeichnen): * Eine Funktion ''spirale'' mit vier Parametern: Der Funktionsaufruf ''spirale(80, 1, 2, 61)'' soll eine Spirale aus 80 Segmenten mit Anfangslänge 1, Veränderung 2 und Abbiegewinkel 61 zeichnen (also die leicht verdrehte hexagonale Spirale im obigen Screenshot). * Eine Funktion '' bewege_unsichtbar'' mit zwei Parametern: Der Funktionsaufruf ''bewege_unsichtbar(-200, 200)'' soll die Turtle ohne zu zeichnen auf die Position (-200, 200) bewegen. from turtle import * def spirale(n, a, veraenderung, winkel): # # Ergänze hier den "Funktionsrumpf" der Funktion "spirale", # also den Code, der eine Spirale abhängig # von den obigen Parametern zeichnet. # # Ergänze hier die Definition der Funktion "bewege_unsichtbar". # Hinweis: Verwende die Funktion "setpos(x,y)". speed(0) bewege_unsichtbar(200, 200) spirale(40, 10, 5, 90) bewege_unsichtbar(-200, 200) spirale(30, 10, 5, 360/6) bewege_unsichtbar(-200, -200) spirale(80, 1, 2, 61) bewege_unsichtbar(200, -200) spirale(150, 1, 0.3, 360/20) exitonclick() from turtle import * def spirale(n, a, veraenderung, winkel): for index in range(n): forward(a + index * veraenderung) left(winkel) def bewege_unsichtbar(x, y): penup() setpos(x, y) pendown() speed(0) bewege_unsichtbar(200, 200) spirale(40, 10, 5, 90) bewege_unsichtbar(-200, 200) spirale(30, 10, 5, 360/6) bewege_unsichtbar(-200, -200) spirale(80, 1, 2, 61) bewege_unsichtbar(200, -200) spirale(150, 1, 0.3, 360/20) exitonclick() ===== Link zur Kursseite ===== [[lehrkraefte:snr:informatik:glf22|Zur Kursseite]]