K103: Einführung in Funktionen

Mit Funktionen können wir Anweisungen zusammenfassen und ihnen einen Namen geben.

Inhaltsverzeichnis

Einordnung

Kursblog L10T1: Einführung in Funktionen

Dieser Blog wird vom IAIP gratis zur Verfügung gestellt. Der Blog ist ein Bestandteil des Kurses K103 «Programmieren mit Turtle Graphics» und gehört zur Lektion 10, Themenblock 1 (L10T1).

Der Kurs führt dich durch die einzelnen Blogs, enthält Zusatzmaterialien und Quizze zur Lernkontrolle. Der Kurs hat eine Kursgebühr von CHF 50.- Mit dem Einschreiben zum Kurs hilfst du mit, dass solche Blogs auch zukünftig noch gratis zur Verfügung gestellt werden können.

Rückblick

In den letzten 9 Kapiteln haben wir die Grundlagen der Programmierung erarbeitet. Wir haben Programme entworfen, indem wir Anweisungen aufgeschrieben und anschliessend Python zur Übersetzung in Maschinensprache gegeben haben. Python bzw. der Computer hat eine Zeile nach der anderen, von oben nach unten, abgearbeitet (Programmstruktur: Sequenz). Wir haben ebenfalls gesehen, dass es beim Programmieren sogenannte Kontrollstrukturen wie Schleifen (for-Schleife, while Schleife: Programmstruktur Iteration) oder Verzweigungen (if-else; if – elif- else: Programmstruktur Selektion) gibt. Kontrollstrukturen erlauben es, den Ablauf der Anweisungen zu kontrollieren. Man kann Befehle mehrmals nacheinander wiederholen oder etwa nur dann ausführen lassen, wenn eine gewisse Bedingung erfüllt ist. 

In dieser Lektion liegt der Schwerpunkt bei Funktionen. Mit Funktionen können wir Anweisungen zusammenfassen und ihnen einen Namen geben. Wir können so unsere eigenen «Befehle» erstellen. 

Schwerpunkte

  • Erstes Kennenlernen von Funktionen
  • allgemeine Syntax und Funktionsweise von Funktionen

Einführung in Funktionen

Einführendes Beispiel mit Turtle Graphics

Funktionen zu Programmieren ist einfacher als es klingt. Beginnen wir in gewohnter Weise mit einem kleinen Beispiel. Basis bildet eine Figur aus Lektion 3, welche aus vier gezeichneten Quadraten besteht.

Der zugehörige Programmcode ist nachfolgend abgebildet.

from turtle import *

# los geht's: erstes Quadrat
forward(100)
right(90)
forward(100)
right(90)
forward(100)
right(90)
forward(100)

penup()
forward(10)
pendown()

# zweites Quadrat
forward(100)
right(90)
forward(100)
right(90)
forward(100)
right(90)
forward(100)

penup()
forward(10)
pendown()

# drittes Quadrat
forward(100)
right(90)
forward(100)
right(90)
forward(100)
right(90)
forward(100)

penup()
forward(10)
pendown()

# viertes Quadrat
forward(100)
right(90)
forward(100)
right(90)
forward(100)
right(90)
forward(100)


# und Abschluss
exitonclick()

Ein ziemlich langes Programm für eine so einfache Figur! Bei der Figur und auch im Programm fällt auf, dass die Figur bzw. das Programm aus 4 identischen Elementen besteht. Die Figur setzt sich aus 4 genau gleichen Quadraten zusammen. Hier kommen Funktionen zum Zuge. Mit Funktionen können wir ein einzelnes Element definieren, diesem einen Namen geben und anschliessend den Namen verwenden. Anstelle dem Computer vier Mal nacheinander jeden einzelnen Schritt, wie man ein Quadrat zeichnet, mitzuteilen,  können wir also dem Computer beibringen, was ein «Quadrat» ist, und ihn dann bitten, 4 Mal ein Quadrat zu zeichnen. Das Ganze sieht so aus: 

from turtle import *

def quadrat():
    forward(100)
    right(90)
    forward(100)
    right(90)
    forward(100)
    right(90)
    forward(100)

quadrat()

penup()
forward(10)
pendown()

quadrat()

penup()
forward(10)
pendown()

quadrat()

penup()
forward(10)
pendown()

quadrat()

exitonclick()

In den Zeilen 3-10 bringen wir dem Computer bei, wie man ein Quadrat zeichnet. In Zeile 3 beginnen wir die Funktionsdefinition mit der Anweisung def quadrat():, was übersetz etwa soviel bedeutet wie: hier kommt die Definition, was ein quadrat ist. Anschliessend (Zeilen 4-10) folgen die Anweisungen. Sobald der Computer weiss, was ein quadrat ist, können wir in den Zeilen 12, 18, 24 und 30 unser Quadrat verwenden. Im selben Stil können wir übrigens auch eine Funktion für die «Lücken» zwischen den Quadraten definieren und verwenden. So erhalten wir ein deutlich kürzeres und auch verständlicheres Programm.

from turtle import *

def quadrat():
    forward(100)
    right(90)
    forward(100)
    right(90)
    forward(100)
    right(90)
    forward(100)
    
def lücke():
    penup()
    forward(10)
    pendown()

quadrat()
lücke()
quadrat()
lücke()
quadrat()
lücke()
quadrat()

exitonclick()

Einführendes Beispiel ohne Turtle Graphics

Beginnen wir in gewohnter Weise mit einem kleinen Beispiel. Im englischsprachigen Raum werden Längen oftmals in Inch (oder Zoll) anstelle von in cm angegeben. Dabei entsprechen einem Inch (oder 1 Zoll) genau 2.54cm. 2 Inch sind somit 5.08cm etc. Wir möchten nun ein kleines Programm schreiben, welches uns den korrekten  Umrechnungsfaktor angibt.

def inch():
    print("1 Inch ist 2.54cm")

inch()

In den Zeilen 1 & 2 definiert unser Programm, was der Computer unter dem Namen inch() verstehen soll. Im Beispiel bedeutet inch() einfach nur, dass er «1 Inch ist 2.54cm» auf den Bildschirm schreiben soll. Nachdem der Name inch() erst einmal definiert wurde, können wir ihn in Zeile 4 verwenden.  Das Programm führt zu folgender Ausgabe:

Wir haben gewissermassen einen «neuen Befehl» erstellt. Einmal erstellt, können wir diesen beliebig oft verwenden. Beachte also: bis anhin hatte Python keine Ahnung, was es machen soll, wenn jemand irgendwo in einem Programm die Anweisung inch() eingibt. 

Allgemeine Definition und Syntax einer Funktion

Die Syntax einer Funktion (ohne Parameter und Rückgabewerte) in Python ist wie folgt:

 def funktionsname():
         Anweisung 1
         Anweisung 2
         Anweisung 3

In Python erstellt bzw. definiert man eine neue Funktion mit dem Schlüsselwort def. Es leitet die Funktionsdefinition ein. Nach dem Schlüsselwort steht der Name der Funktion, gefolgt von runden Klammern () und einem Doppelpunkt : am Ende der Anweisung. Diese erste Zeile repräsentiert den Kopf der Funktion. Das ist vom Prinzip her genau gleich wie beim Kopf der for-Schleife (siehe Lektion 7), dem Kopf bedingter Anweisungen und Verzweigungen (siehe Kapitel 8) etc.

Die beim Aufruf der Funktion auszuführenden Anweisungen werden eingerückt auf den Folgezeilen notiert, so wie wir dies ebenfalls bereits von bedingten Anweisungen und Schleifen kennen. Durch die Strukturierung erkennt der Python Interpreter, welche Anweisungen zur Funktion gehören (Strukturierung durch Einschub/ Identation). Theoretisch könnte man die Anweisungen gleich anschliessend an die Funktionsdefinition schreiben und durch Strichpunkte abtrennen. Davon ist aber grundsätzlich abzuraten. Es entspricht weder der Praxis noch einem guten Programmierstil.

Merke dir:

Ergänzende Informationen für fortgeschrittene Kursteilnehmer:

Zur guten Praxis gehört ferner ebenfalls, zumindest wichtige oder komplexere Funktionen mit einem DocString zu beschreiben. DocStrings sind wie Kommentare, können aber im Unterschied zu reinen Kommentaren automatisiert ausgelesen werden. Diese ein- oder mehrzeilige Beschreibung steht jeweils zwischen 3 Anführungs- und Schlusszeichen «»» bzw. »› und wird gleich nach dem Funktionskopf eingefügt. Unseren einfachen Anschauungscodes sind weitgehend selbstsprechend. Wir werden daher in der Regel auf die Verwendung von DocStrings verzichten. 

def quadrat():
    """Funktion zeichnet ein Quadrat """

    # Anweisung 1
    # Anweisung 2
    # ...
    

Aufruf einer Funktion

Einmal definiert können Funktionen beliebig oft aufgerufen werden. Der geschriebene Code ist wiederverwendbar. Um eine Funktion aufzurufen, verwenden man einfach den Funktionsnamen mit nachgestellten Klammern.

funktionsname()

Position der Funktionsdefinition im Programm

Der Computer arbeitet eine Anweisung nach der anderen ab. Es ist daher wichtig, dass die Funktion auch vor ihrem Aufruf definiert wurde. Ansonsten würde man einen Namen aufrufen, welcher der Computer noch gar nicht kennt.

Richtige Reihenfolge (Funktionsdefinition vor Aufruf)

...
def quadrat():
    forward(100)
    right(90)
    forward(100)
    right(90)
    forward(100)
    right(90)
    forward(100)

quadrat()
...

FALSCHE Reihenfolge (Funktionsdefinition nach Aufruf)

...
quadrat()
...
def quadrat():
    forward(100)
    right(90)
    forward(100)
    right(90)
    forward(100)
    right(90)
    forward(100)

...

Funktionen werden identifiziert über ihre Namen. Wird eine Funktion aufgerufen, so muss Python den verwendeten (Funktions-) Namen erkennen. Er muss bereits zum Wortschatz (zur Lexik) der Programmiersprache gehören ( d.h. die Funktionsdefinition muss vorab vom Interpreter ausgeführt worden sein). Versucht man eine Funktion vor ihrer Definition aufzurufen, so meldet Python «NameError: name ‹….› is not defined». Der Interpreter weiss nicht, was dieser Namen bedeuten soll. 

Der Aufbau eines Programms wird mit zunehmenden Möglichkeiten komplexer. An dieser Stelle kannst du dir aber folgender «grundsätzlicher» Aufbau merken:

Ein solcher Aufbau ist in der Regel richtig und entspricht auch einem guten Programmierstil, bei welchem man sich einfach und schnell in einem Programm zurechtfindet.

Ergänzende Informationen für fortgeschrittene Kursteilnehmer:

Das Schlüsselwort def ist ein so genanntes ausführbares Kommando (engl.: executable statement). Es legt bei Ausführung die Funktion an, d.h. vor dieser Ausführung existiert die Funktion nicht. Für gewöhnlich stellt man daher sämtliche Funktionen zusammen an den Anfang des Quellcodes. Grundsätzlich kann aber die Funktion irgendwo im Code definiert werden, solange die Definition vor dem Funktionsaufruf ausgeführt wird. Die folgenden 2 Beispiele sind beide korrekt, wobei das linke Beispiel einer guten Praxis entspricht

# Funktionsdefinitionen

def welcome():
    print("Herzlich Willkommen")
    print("Ich bin dein Computer")


def persönlich(name):
    print("Guten Tag", name + ".")


# Aufruf der Funktionen aus Hauptteil
welcome()
persönlich("Hans")

# Funktionsdefinitionen

def welcome():
    print("Herzlich Willkommen")
    print("Ich bin dein Computer")

welcome()

def persönlich(name):
    print("Guten Tag", name + ".")

persönlich("Hans")

Parameter

Richtig nützlich werden Funktionen erst, wenn man mit Parametern arbeitet. Dadurch kann man gewisse Werte an eine Funktion übergeben.

Einführendes Beispiel mit Turtle Graphics​

Betrachten wir als erstes wiederum unser Programm mit den 4 Quadraten. Dieses Mal leicht angepasst. Studiere den nachfolgenden Code (links) und vergleiche diesen mit dem alten Programm (rechts).

Programm mit Parametern (neu, angepasst)

from turtle import *

def quadrat(länge):
    forward(länge)
    right(90)
    forward(länge)
    right(90)
    forward(länge)
    right(90)
    forward(länge)
    
def lücke(abstand):
    penup()
    forward(abstand)
    pendown()

quadrat(80)
lücke(10)
quadrat(80)
lücke(10)
quadrat(80)
lücke(10)
quadrat(80)

exitonclick()

Programm ohne Parameter (alt, siehe oben)

from turtle import *

def quadrat():
    forward(100)
    right(90)
    forward(100)
    right(90)
    forward(100)
    right(90)
    forward(100)
    
def lücke():
    penup()
    forward(10)
    pendown()

quadrat()
lücke()
quadrat()
lücke()
quadrat()
lücke()
quadrat()

exitonclick()

Was ist anders? Bei der Funktionsdefinition in Zeile 3 schreiben wir anstelle von def quadrat(): neu def quadrat(länge). Und beim Aufruf dieser Funktion schreiben wir (Zeile 17) neu quadrat(80). Wir rufen also nicht nur die Funktion auf, sondern übergeben gleichzeitig noch einen Wert. Dieser Wert wird dann automatisch in der Variable länge abgespeichert. Dadurch sind wir neu in der Lage, mit ein und derselben Funktion unterschiedlich grosse Quadrate zu zeichnen. Probieren wir es einmal aus und verändern die Werte in den Zeilen 17-23:

from turtle import *

def quadrat(länge):
    forward(länge)
    right(90)
    forward(länge)
    right(90)
    forward(länge)
    right(90)
    forward(länge)
    
def lücke(abstand):
    penup()
    forward(abstand)
    pendown()

quadrat(100)
lücke(20)
quadrat(80)
lücke(10)
quadrat(60)
lücke(5)
quadrat(40)

exitonclick()

Einführendes Beispiel ohne Turtle Grafiks

Betrachten wir nun unser Programm mit den Informationsangaben zu Inches (Zoll). Dieses Mal leicht angepasst. Studiere den nachfolgenden Code (links) und vergleiche diesen mit dem alten Programm (rechts)

def inch(länge):
    in_cm = 2.54 * länge
    print("Das sind " + str(in_cm) + "cm")

inch(5)

def inch():
    print("1 Inch ist 2.54cm")

inch()

Was ist anders? Unsere neue Funktion ermittelt die Länge in cm für eine gegebene Länge in Inches.  In Zeile 5 rufen wir die Funktion auf, übergeben aber gleichzeitig noch einen Wert (im Beispiel die Ganzzahl 5). In der Funktionsdefinition (Zeile 1) müssen wir daher noch sagen, was Python mit diesem Wert anstellen soll. Der Wert soll automatisch in der Variable länge abgespeichert werden, so dass wir diesen dann in der Funktion verwenden können.

Wir können übrigens auch mehrere Werte übergeben. Das folgende Beispiel berechnet den Umfang eines Rechtecks:

def rechteck(a, b):
    umfang  = a + b + a + b
    print("Länge des Rechtecks :", a)
    print("Breite des Rechtecks:", b)
    print("Umfang des Rechtecks:", umfang)

Ist die Funktion einmal angelegt (Quellcode bzw. Funktionsdefinition ausgeführt), so haben wir unseren eigenen «Befehl» zur Berechnung des Umfang eines Rechtecks erstellt. Wir können diesen aus dem Quellcode heraus, oder auch direkt in der Shell aufrufen. 

Allgemeine Definition und Syntax einer Funktion mit Parametern

Wir werden im nächsten Themenblock die Parameterübergabe im Detail erläutern. Für diese erste Einführung kann man sich merken, dass in Python auch Werte an Funktionen übergeben werden können. Diese Werte lassen sich dann innerhalb der Funktion verwenden. Die «erweitere» Syntax einer Funktion (mit Parameter, aber noch ohne Rückgabewerte) ist wie folgt

 def funktionsname(parameter):
         Anweisung 1
         Anweisung 2
         Anweisung 3

Zwischen den Klammer () werden also die Parameter, falls es solche gibt, aufgelistet. Parameter sind hier lediglich Namen für die Variablen (Objekte), welche wir dann in der Funktion verwenden möchten. Dank solcher Parameter kann man beim Aufruf Werte (Objekte) an eine Funktion übergeben und dann innerhalb des Funktionscodes nutzen. Gibt es mehrere Parameter, so trennt man die einzelnen Namen durch Kommas.

Zusammenfassend gilt:

Rückgabewerte

Man kann nicht nur Werte an eine Funktion übergeben, sondern auch Rückgabewerte aus einer Funktion herausreichen. Hierzu nutzt man das Schlüsselwort return. Wir werden das Thema Rückgabewerte ebenfalls noch vertiefen. Hier geht es lediglich um ein kleines Beispiel zur Illustration. Basis bildet unser Längenumrechnungsprogramm. Wir wollen neu, dass es uns die Länge in cm als Wert zurückgibt, anstelle diesen Wert direkt auf den Bildschirm zu schreiben.

def inch(länge):
    in_cm = 2.54 * länge
    return in_cm

inch(10)

Beachte die return Anweisung in Zeile 3. Das Programm ist inhaltlich korrekt, allerdings passiert noch nicht viel. Wie müssen Python noch mitteilen, was es mit dem zurückgegebenen Wert machen soll. Ansonsten geht dieser verloren. Normalerweise speichert man diesen durch eine Zuweisung an eine Variable ab (siehe nachfolgend Zeile 5). Wir können dann die Variable mittels print() ausgeben (siehe nachfolgend Zeile 6 im linken Beispiel), oder beispielsweise mit dieser noch arbeiten, bevor wir etwas ausgeben.

def inch(länge):
    in_cm = 2.54 * länge
    return in_cm

cm = inch(10)
print("10 Inches sind cm: ", cm)

def inch(länge):
    in_cm = 2.54 * länge
    return in_cm

m = inch(10) / 100
print("10 Inches sind in Meter: ", m)

Im Beispiel wird beim Aufruf inch(i) ein Wert für den Funktionsparameter länge  übergeben und der umgerechnete Wert aus der Funktion herausgereicht. 

def inch(länge):
    in_cm = 2.54 * länge
    return in_cm

for i in range(1, 5):
    cm = inch(i)
    print(i, "Inches sind cm: ", cm)

Ergänzung: Sinn und Zweck von Funktionen

Moderne Programmiersprachen erlauben es, bestimmte Befehlsfolgen wie gezeigt unter einem Namen abzulegen und dann bei Bedarf über diesen Namen aufzurufen. Hierzu verwendet man sogenannte «Funktionen», «Prozeduren», «Subroutinen» oder auch «Methoden». In Python sind diese Begriffe weitgehend identisch. Wir sprechen im Rahmen dieser Einführung lediglich von Funktionen und von Methoden. Gemeint ist dabei jeweils dasselbe.  

Doch weshalb benötigt man eigentlich Funktionen? Die Verwendung von Funktionen hat hier 2 wesentliche Begründungen:

1. Strukturierung von Code:

Einerseits können Funktionen verwendet werden, um den Code zu strukturieren. Der Begriff strukturieren ist hier nicht mit den in den vorangehenden Kapiteln vorgestellten Kontrollstrukturen (Schleifen, bedingte Anweisungen & Verzweigungen) zu verwechseln, welche den Programmablauf kontrollieren bzw. steuern. Strukturieren bedeutet hier, logisch zusammenhängende Blöcke zu bilden und unter einem Namen abzulegen.

Angenommen man programmiert ein kleines Spiel, welches über ein Spielmenü gesteuert wird. Man hat dann irgendeine Art von Schlaufe, und je nach Auswahl eines Menüpunkts wird der zu diesem Menüpunkt zugehörige Code ausgeführt.

while True:
    print("1: Neues Spiel")
    print("2: Spieler wechseln")
    print("3: Rangliste")
    # .....
    print("8: Anleitung")
    print("9: Spiel beenden")
    
    wahl = input("Bitte wählen Sie einen Menüpunkt: ")
    if wahl == "1":                          
        # hier kommt der Spielcode
        # ...
        # ca. 100 Zeilen...
    elif wahl == "2":                        
        # hier kommt wieder viel Code um den Spieler zu wechseln
    elif wahl == "3":                       
        # hier kommt der Code, um die Rangliste anzuzeigen
        #...
    
    #... etc.
    
    elif wahl == "9":                        # Beenden
        s = input("Sind Sie sicher? (y/n) ")
        if s == "y":
            break

Beginnt man nun die einzelnen Programmteile zu programmieren, dann wird es schnell offensichtlich, dass das Menü, welches gewissermassen den roten Faden bildet, schon bald über mehrere hundert Codezeilen verteilt ist. Arbeitet man aber anstelle dessen mit Funktionen, so braucht man unter der jeweiligen if/elif Anweisung bloss eine Zeile, namentlich den Funktionsaufruf, einzufügen. Der Hauptteil des Programms bleibt kompakt und übersichtlich – das Programm ist strukturiert.

2. Vermeidung von Redundanz (Verdoppelung von Codezeilen)

Zweitens kann über Funktionen eine unnötige Verdopplung von Programmtext vermieden werden. Wir haben bereits Beispiele gesehen, wo ein und dieselbe Funktion mehrmals aufgerufen wird.

Diese Strukturierung von Programmcode mittels Funktionen erleichtert übrigens auch das Testen von Programmen. Funktionalität kann nämlich so gekapselt und als «Black Box» realisiert werden. Auf Basis der Eingabeparametern untersucht man dann, welche Ergebnisse bzw. Seiteneffekte generiert werden.

Und das verhindern von doppeltem (redundanten) Programmcode bezieht sich letzten Endes nicht nur auf ein einziges Programm. Man kann «Bibliotheken» von häufig gebrauchten Funktionen aufstellen und diese dann in verschiedenen Programmen verwenden. Das spart Zeit und reduziert die Wahrscheinlichkeit von Fehlern, da man sich auf bereits erprobten Code verlassen kann, statt das Rad immer wieder neu erfinden zu müssen.

Übungsaufgaben

Nachfolgend findest du ausgewählte Übungsaufgaben. 

Aufgabe 1a: Dreieck

Erstelle eine Funktion dreieck(), welche beim Aufruf ein gleichseitiges Dreieck mit der Seitenlänge 100 zeichnet.

Hinweis: Du kannst alle Anweisungen einzeln eingeben oder auch das Programm mit einer for-range Schleife etwas abkürzen.

Aufgabe 1b: Drei Dreiecke (Dreieck mit Parameter)

Erweitere nun unser Programm aus Aufgabe 1a. Neu hat unsere Funktion dreieck() einen Parameter länge. Dieser soll bestimmen, wie gross unser Dreieck ist (bzw. wie lang eine Seite ist). Der Aufruf dreieck(90) soll beispielsweise ein gleichseitiges Dreieck mit Seitenlänge 90 zeichnen.

Zeichne dann die rechts abgebildete Figur. Es sind 3 nacheinander gezeichnete Dreiecke mit den Seitenlängen 100, 80 und 60. Du musst also 3x die Funktion dreieck aufrufen, wobei du jedes mal einen anderen Wert übergibst.

Aufgabe 1c: Spirale aus Dreiecken

Versuche die rechts abgebildete Spirale zu zeichnen. Sie besteht aus 100 Dreiecken der Seitenlängen 0, 2, 4, 6, 8, 10, 12, 14, … , 198

Hinweis: Zwischen den einzelnen Dreiecken muss man jeweils etwas nach links drehen. Beispielsweise mit left(2).

Aufgabe 2a: Rechteck

Versuche das rechts abgebildete Rechteck zu zeichnen. Es hat die Seitenlängen 200 und 100 Punkte. Schreibe hierzu die Funktion rechteck(). 

Hinweis: Drehe dabei jeweils nach rechts und drehe insgesamt 4x, so dass unsere Schildkröte am Ende wieder nach rechts blickt. Schreibe jede Anweisung einzeln auf (also keine for-Schleife etc.). Das heisst, der Rumpf der Funktion besteht aus 8 Anweisungen.

Aufgabe 2b: Rechteck mit 1 Parameter

Grundlage bildet unser Rechteck aus Aufgabe 2a. Wir bezeichnen die längere Seite als Seite a. Schreibe nun deine Funktion so um, dass man die Seitenlänge von a beim Funktionsaufruf bestimmen kann. Die Anweisung rechteck(300) zeichnet dann ein Rechteck mit Länge 300 und Höhe bzw. Breite 100. Siehe Bild rechts oben. 

Zeichne nun nacheinander 5 Rechtecke mit den Längen 200, 180, 160, 140 und 120, so wie im Bild rechts unten dargestellt.

Hinweis: Wir können also nur eine Seite verändern. Die Höhe des Rechtecks ist immer 100 Punkte.

Aufgabe 2c: Rechteck mit 1 Parameter II

Grundlage bildet unser Rechteck aus Aufgabe 2b. Wir bezeichnen die längere Seite wiederum mit a. Schreibe nun deine Funktion so um, dass man die Seitenlänge von a beim Funktionsaufruf bestimmen kann. Die Höhe des Rechtecks ist nun aber neu immer genau die Hälfte der Länge. Die Anweisung rechteck(300) zeichnet dann ein Rechteck mit Länge 300 und Höhe bzw. Breite 150. Siehe Bild rechts oben. 

Zeichne nun nacheinander 5 Rechtecke mit den Längen 200, 180, 160, 140 und 120, so wie im Bild rechts unten dargestellt.

Hinweis: Unsere Funktion hat nur 1 Parameter mit dem Namen a. Innerhalb des Funktionsrumpfs verwenden wir dann diese Variable mit der Bezeichnung a.

Aufgabe 2d: Rechteck mit 2 Parameter

Grundlage bildet unser Rechteck aus den vorangehenden Aufgaben. Neu möchten wir beim Funktionsaufruf Länge und Breite des Rechtecks frei wählen können. 

Der Aufruf rechteck(200, 30) soll uns also beispielsweise ein Rechteck mit der Seitenlänge von 200 Punkten und der Höhe von 30 Punkten zeichnen. Beachte, dass wir jetzt 2 Variablen bzw. 2 Funktionsparameter haben. Bezeichne diese mit den Namen a und b. Zeichne dann nacheinander 4 Rechtecke mit den Aufrufen: 
  rechteck(200, 100) 
  rechteck(150, 90)
  rechteck(100, 30)

Zusatzaufgabe:  Versuche nun das Programm so zu ergänzen, dass wir auch noch eine Farbe übergeben können. Die Rechtecke werden dann in der entsprechenden Farbe ausgefüllt. Das Bild rechts unten sollte enstehen, wenn wir die folgenden 3 Anweisungen eingeben:
  rechteck(200, 100, «red») 
  rechteck(150, 90, «green»)
  rechteck(100, 30, «blue»)

Aufgabe 2e: Teppich aus Rechtecken

Grundlage bildet unser Rechteck aus den vorangehenden Aufgaben 2d. Wir möchten nun einen «Teppich» aus zufälligen Rechtecken erstellen.

Hierzu erstellst du eine Schlaufe, welche beispielsweise 1000x ausgeführt wird. Bei jedem Durchgang bewegst Du die Schildkröte an eine beliebige Position und zeichnest anschliessend das Rechteck. Das Rechteck hat eine zufällige Länge und Breite, sowie eine zufällige Farbe:

from turtle import *
import random

# .....
# hier kommt die Funktion speed(0) farben = ["red", "orange", "yellow", "green", "blue", "purple"] for i in range(1000): penup() x=random.randint(-300,300) y=random.randint(-300,300) goto(x,y) pendown() # hier geht es weiter
# ..........
farbnummer = random.randint(0, 5) rechteck(a, b, farben[farbnummer]) exitonclick()

Ergänze das Programm.

Aufgabe 3a: ein Baum

Erstelle eine Funktion baum(), welche beim Aufruf einen Baum zeichnet. Am Ende bewegst du die Schildkröte wieder in die Mitte des Bildschirms mit Blickrichtung nach rechts.

Hinweis: 

  • pensize(wert) stellt die Siftdicke ein.
  • pencolor(«brown») bzw. pencolor(«darkgreen») stellt die Farbe des Zeichenstifts auf braun bzw. dunkelgrün ein.
  • begin_fill() und end_fill werden benötigt, damit eine Figur ausgefüllt wird. fillcolor(«green») stellt die Füllfarbe auf grün ein.

Aufgabe 3b: Baum mit variabler Grösse

Erweitere nun unser Programm aus Aufgabe 2a. Neu hat unsere Funktion baum() einen Parameter grösse. Dieser soll bestimmen, wie gross unser Baum ist. Dabei gilt:

  • Dicke des Baumstamms: 2x die Grösse
  • Länge des Baumstamms: 5x die Grösse
  • Radius der Baumkrone (Kreis): 5x Grösse + 10 Punkte
  • Umrandung des Kreises: Ein Zehntel der Grösse (Grösse/10)

Zeichne dann die rechts abgebildete Figur. Es sind 3 Bäume der Grösse 20, 10 und 5

Aufgabe 3c: Baum mit mehreren Parametern

Wir können in einer Funktion auch mehrere Parameter verwenden. Schreibe nachfolgend die Funktion baum(grösse, x, y). Der erste Parameter grösse bestimmt die Grösse des Baums, der zweite Parameter x seine x-Position und der dritte Parameter y seine y-Position.

Zeichne dann die rechts abgebildete Figur. Es sind 3 Bäume Grösse 20, 10 und 5. Der grösste Baum ist unten links, der kleinste Baum oben rechts.

Aufgabe 3d: Zusatzaufgabe Wald

Versuche unser Beispiel etwas auszubauen. Beispielsweise indem du einen ganzen Wald voller Bäume erstellst. 

Zeichne hierzu 50 Bäume, wobei die Grösse und die Position jedes Baums zufällig gewählt werden.

Aufgabe 3e: Zusatzaufgabe Anzucht

Du kannst es auch etwas weniger chaotisch haben. Beispielsweise in einer Baumplantage, wo die einzelnen Bäume immer denselben Abstand haben. Oben (hinten im Bild) sind dann die kleineren Bäume, nach unten (vorne) wird die Baumreihe immer grösser.

Aufgabe 5: Begrüssung

Schreibe ein Funktion hallo(), welche eine Person begrüsst. Erweitere dann die Funktion so, dass jeweils ein Name und eine Mitgliederliste übergeben werden.  Handelt es sich beim Namen um ein Mitglied aus der Liste, so erscheint ein anderer Begrüssungstext.

Aufgabe 5c: Begrüssung mit Rückgabewert

Übergeben wird nun neu auch eine Liste bereits begrüsster Personen, welche anschliessend an die Begrüssung ergänzt zurückgegeben wird. Verschiedenen Begrüssungstexte tragen dem Umstand Rechnung, ob jemand schon begrüsst wurde und oder Mitglied ist.

Aufgabe 13: Kreisumfang und Kreisfläche

Schreibe ein Funktion Kreis(radius), welche in Abhängigkeit des Radius den Kreisumfang (2πr) und die Kreisfläche (r2 π) berechnet und als Rückgabewerte zurückreicht.

Hinweis: Man kann innerhalb der Funktion die Variable pi = 3.14159 definieren.

Aufgabe 14: Mathematische Fakultät

Schreibe ein Funktion fak_iter(n), welche die Fakultät n! einer Ganzzahl n berechnet. Bsp.: Die Fakultät von 4 ist 4! = 4*3*2*1 = 24

Lösungen zu den Übungsaufgaben

Lösung zur Aufgabe 1a: Dreieck

Nachfolgend findest du das Programmbeispiel:

from turtle import *

def dreieck():
    forward(100)
    left(120)
    forward(100)
    left(120)
    forward(100)
    left(120)

dreieck()
exitonclick()

Hinweis:  Innerhalb der Funktion machen wir ebenfalls 3x genau dasselbe. Idealerweise kürzt man die Anweisungen im Funktionsrumpf ab, indem man eine Schleife verwendet. In unserem Fall ein for-Schleife: 

from turtle import *

def dreieck():
    for i in range(3):
        forward(100)
        left(120)

dreieck()
exitonclick()

Ein besonderes Augemerk ist auf die Einschübe zu richten.

Lösung zur Aufgabe 1b: Drei Dreiecke (Dreieck mit Parameter)

Nachfolgend findest du das Programmbeispiel:

from turtle import *

def dreieck(länge):
    forward(länge)
    left(120)
    forward(länge)
    left(120)
    forward(länge)
    left(120)

dreieck(100)
dreieck(80)
dreieck(60)
exitonclick()

Hinweis: Idealerweise kürzt man die Anweisungen im Funktionsrumpf wiederum ab, indem man eine Schleife verwendet. 

from turtle import *

def dreieck(länge):
    for i in range(3):
        forward(länge)
        left(120)

dreieck(100)
dreieck(80)
dreieck(60)

exitonclick()

Ein besonderes Augemerk ist auf die Einschübe zu richten.

Lösung zur Aufgabe 1c: Spirale aus Dreiecken

Nachfolgend findest du das Programmbeispiel:

from turtle import *

def dreieck(länge):
    for i in range(3):
        forward(länge)
        left(120)

for j in range(100):
    dreieck(j*2)
    left(2)

exitonclick()

In den Zeilen 8-10 haben wir eine for-Schleife. Sie generiert die Werte j= 0, 1, 2, 3, 4, 5, .. , 99 . In Zeile 9 wird dann die Funktion aufgerufen, wobei man jeweils den doppelten Wert nimmt.

Hinweis:  Besonders schöne Spiralen entstehen, wenn man zusätzlich zur Anweisung left(2) noch eine kleine Vorwärtsbewegung, z.B. mit forward(2), einbaut.

Lösung zur Aufgabe 2a: Rechteck

Nachfolgend findest du das Programmbeispiel:

from turtle import *

def rechteck():
    forward(200)
    right(90)
    forward(100)
    right(90)
    forward(200)
    right(90)
    forward(100)
    right(90)

rechteck()

exitonclick()

Lösung zur Aufgabe 2b: Rechteck mit 1 Parameter

Nachfolgend findest du das Programmbeispiel:

from turtle import *

def rechteck(a):
    forward(a)
    right(90)
    forward(100)
    right(90)
    forward(a)
    right(90)
    forward(100)
    right(90)

rechteck(200)
rechteck(180)
rechteck(160)
rechteck(140)
rechteck(120)

exitonclick()

Hinweis:  Beachte, dass die Variable a nur bei jeder zweiten forward() Anweisung  eingesetzt wird. Nur bei jenen, welche für die Seitenlängen verantwortlich sind. Die Höhe des Rechtecks bleibt 100 Punkte.

Lösung zur Aufgabe 2c: Rechteck mit 1 Parameter II

Nachfolgend findest du das Programmbeispiel:

from turtle import *

def rechteck(a):
    forward(a)
    right(90)
    forward(a/2)
    right(90)
    forward(a)
    right(90)
    forward(a/2)
    right(90)

rechteck(200)
rechteck(180)
rechteck(160)
rechteck(140)
rechteck(120)

exitonclick()

Hinweis:  Beachte, dass die Variable a nur bei jeder forward() Anweisung  verwendet wird. Bei der Bewegung zur Höhe des Rechtecks dividieren wir die Variable jeweils durch 2. Alternativ könntest du auch innerhalb der Funktion eine zweite Variable b definieren und dann diese verwenden.

def rechteck(a):
    b = a / 2
    forward(a)
    right(90)
    forward(b)
    right(90)
    forward(a)
    right(90)
    forward(b)
    right(90)

Lösung zur Aufgabe 2d: Rechteck mit 2 Parameter

Nachfolgend findest du das Programmbeispiel:

from turtle import *

def rechteck(a, b):
    forward(a)
    right(90)
    forward(b)
    right(90)
    forward(a)
    right(90)
    forward(b)
    right(90)

rechteck(200, 100)
rechteck(150, 90)
rechteck(100, 30)

exitonclick()

Zusatzaufgabe:  Nachfolgend steht die Lösung zur Zusatzaufgabe. Beachte hier, dass wir nicht nur Zahlenwerte sondern auch andere Datentypen wie beispielsweise Zeichenfolgen übergeben können. Die Farbe ist eine Zeichenfolge und muss deshalb beim Funktionsaufruf ebenfalls zwischen einfachen » oder doppelten «» Anführungs- und Schlusszeichen stehen.

from turtle import *

def rechteck(a, b, color):
    fillcolor(color)
    begin_fill()

    forward(a)
    right(90)
    forward(b)
    right(90)
    forward(a)
    right(90)
    forward(b)
    right(90)

    end_fill()

rechteck(200, 100, "red")
rechteck(150, 90, "green")
rechteck(100, 30, "blue")

exitonclick()

Lösung zur Aufgabe 2e: Teppich aus Rechtecken

Nachfolgend findest du das Programmbeispiel:

from turtle import *
import random

def rechteck(a, b, color):
    fillcolor(color)
    begin_fill()

    forward(a)
    right(90)
    forward(b)
    right(90)
    forward(a)
    right(90)
    forward(b)
    right(90)

    end_fill()

speed(0)
farben = ["red", "orange", "yellow", "green", "blue", "purple"]

for i in range(1000):

    penup()
    x=random.randint(-300,300)
    y=random.randint(-300,300)
    goto(x,y)
    pendown()

    länge = random.randint(5,80)
    breite = random.randint(5,80)
    farbnummer = random.randint(0,5) 
    rechteck(länge, breite, farben[farbnummer])

exitonclick()

Lösung zur Aufgabe 3a: ein Baum

Nachfolgend findest du das Programmbeispiel:

from turtle import *

def baum():

    left(90)
    pensize(20)
    pencolor("brown")
    forward(100)

    right(90)
    pensize(2)
    pencolor("darkgreen")
    fillcolor("green")
    begin_fill()
    circle(100)
    end_fill()

    penup()
    home()
    pendown()

baum()

exitonclick()

Lösung zur Aufgabe 3b: ein Baum mit variabler Grösse

Nachfolgend findest du das Programmbeispiel:

from turtle import *

def baum(grösse):

    left(90)
    pensize(2*grösse)
    pencolor("brown")
    forward(5*grösse)

    right(90)
    pensize(grösse/10)
    pencolor("darkgreen")
    fillcolor("green")
    begin_fill()
    circle(5*grösse+10)
    end_fill()

    penup()
    home()
    pendown()


baum(20)
forward(150)
baum(10)
forward(250)
baum(5)

exitonclick()

Lösung zur Aufgabe 3c: ein Baum mit mehreren Parametern

Nachfolgend findest du das Programmbeispiel:

from turtle import *

def baum(grösse, x, y):

    penup()
    goto(x, y)
    pendown()

    left(90)
    pensize(2*grösse)
    pencolor("brown")
    forward(5*grösse)

    right(90)
    pensize(grösse/10)
    pencolor("darkgreen")
    fillcolor("green")
    begin_fill()
    circle(5*grösse+10)
    end_fill()

    penup()
    home()
    pendown()

baum(20, -200, -100)
baum(10, 0, 0)
baum(5, 100, 80)

exitonclick()

Lösung zur Aufgabe 3d: Zusatzaufgabe Wald

Nachfolgend findest du das Programmbeispiel:

from turtle import *
import random

def baum(grösse, x, y):

    penup()
    goto(x, y)
    pendown()

    left(90)
    pensize(2*grösse)
    pencolor("brown")
    forward(5*grösse)

    right(90)
    pensize(grösse/10)
    pencolor("darkgreen")
    fillcolor("green")
    begin_fill()
    circle(5*grösse+10)
    end_fill()

    penup()
    home()
    pendown()

speed(0)
for i in range(50):
    gr = random.randint(1,20)
    x = random.randint(-350, 350)
    y = random.randint(-350, 150)
    baum(gr, x, y)

exitonclick()

Hinweis:  Als erstes muss man die Bibliothek random importieren. Die Funktion random.randint(a, b) generiert eine Zufallszahl im Wertebereich zwischen a und b.

Lösung zur Aufgabe 3e: Zusatzaufgabe Anzucht

Nachfolgend findest du das Programmbeispiel zum Erzeugen einer einzelnen Baumreihe.

from turtle import *
import random

def baum(grösse, x, y):

    penup()
    goto(x, y)
    pendown()

    left(90)
    pensize(2*grösse)
    pencolor("brown")
    forward(5*grösse)

    right(90)
    pensize(grösse/10)
    pencolor("darkgreen")
    fillcolor("green")
    begin_fill()
    circle(5*grösse+10)
    end_fill()

    penup()
    home()
    pendown()


for i in range(10):
    gr = 2
    x = -350+i*70
    y = 2
    baum(gr, x, y)

exitonclick()

Möchte man mehrere Baumreihen erzeugen, so wiederholt man einfach die Baumreihe mit etwas anderen Werten. Du kannst in unserem Beispiel 5 for – Schleifen nacheinander schreiben, wobei du in jeder Schleife den Wert für gr etwas erhöhst und ein andere y wählst.

speed(0)

for i in range(5):
    gr = 2
    x = -350+i*140
    y = 350 
    baum(gr, x, y)
for i in range(5):
    gr = 5
    x = -350+i*140
    y = 250 
    baum(gr, x, y)
etc.

Etwas eleganter, aber auch anspruchsvoller, ist eine verschachtelte Struktur. Hier benötigt man eine zweite for Schleife. Der Abstand der Baumreihen sollte immer etwas grösser werden. So etwas kann man über Exponentialfunktionen erreichen. Nachfolgend ein kleines Beispiel der erweiterten for-Schleifen:

speed(0)
for j in range(5):
    for i in range(5):
        gr = 2
        x = -350+i*140
        y = 350 - (j+1)**2 * 30 
        baum(2 + 2*j, x, y)
etc.

Lösung zur Aufgabe 5: Willkommen

Nachfolgend findest du das Programmbeispiel. Basis bildet die Funktion hallo(), welche einen Begrüssungstext ausgibt.

def hallo():
    print("Herzlich Willkommen")

Man kann die Funktion nun mit einem Parameter ausstatten. Beispielsweise den Parameter name. 

def hallo(name):
    print("Herzlich Willkommen", name)

Die Funktion kann aus dem Programm heraus (anschliessend an die Definition) oder auch direkt aus der Shell aufgerufen werden. Hierzu schreibt man beispielsweise einfach hallo(«Reto»). Die Erweiterung des Programms sieht dann wie folgt aus:

def hallo(name, members):
    if name in members:
        print("Hallo " + name + ".")
        print("Willkommen zurück!")
    else:
        print("Guten Tag.")
        print("Herzlich Willkommen!")    

members = ["Heinz", "Peter", "Gustav", "Mike", "David"]
person = input("Bitte Name eingeben: ")
hallo(person, members)

Lösung zur Aufgabe 13: Kreisumfang und Kreisfläche

Nachfolgend findest du das Programmbeispiel:

def kreis(r):
    """ Fläche und Umfang eines Kreises"""

    pi = 3.14159
    umfang, fläche = 2*r*pi, r*r*pi
    return umfang, fläche

Zurückgegeben werden hier 2 Werte, namentlich der Kreisumfang und die Kreisfläche. Die zwei Rückgabewerte werden durch ein Komma voneinander getrennt. Entsprechend muss man auch die Rückgaben anschliessend an zwei Namen zuweisen:

berechneter_umfang, berechnete_fläche = kreis(10)

Lösung zur Aufgabe 14: Mathematische Fakultät

Nachfolgend findest du das Programmbeispiel:

def fak_iter(n):
    """ Berechnung der Fakultät n! """

    res = 1
    for i in range(2,n+1):
        res *= i
    return res

print(fak_iter(244))

Es müsste folgende Ausgabe erscheinen: 
14066861585910957825823554248473273151048885515818703610657157599925059305234089260260425074439479099509579055626847051426975689567391221809612995211904405203575892092769392040929881941264620552259816313262701033449644950077839593819278128782325391432464195965545240828715820115153697334450128028820921002528608026140910553627525564314207634671286354529874385772549637093767058133950661601672128467312782847663458526167040000000000000000000000000000000000000000000000000000000000

Lösung zur Aufgabe 15: Fibonacci-Zahlen

Nachfolgend findest du das Programmbeispiel. Beim Code handelt es sich um eine iterative Berechnung der Zahl. Wir werden später noch ein Beispiel einer rekursiven Berechnung sehen.

def fib_iter(n):
    a, b = 0, 1
    for i in range(n):
        a, b = b, a + b
    return a

print(fib_iter(10))

Es müsste folgende Ausgabe erscheinen: 55

Lösung zur Aufgabe 16: Goldener Schnitt mittels Fibonacci - Folge

Nachfolgend findest du das Programmbeispiel. Beim Code handelt es sich um eine iterative Berechnung der Zahl. Wir werden später noch ein Beispiel einer rekursiven Berechnung sehen.

def fib_iter(n):
    a, b = 0, 1
    for i in range(n):
        a, b = b, a + b
    return a

print(fib_iter(10))

Es müsste folgende Ausgabe erscheinen: 55

Comments