Version 1 vom 28.01.2021
Changelog:
TODO:
Die Codezeile unten enthält an dieses Notebook angepasste Designeinstellungen für Jupyter.
Bei der Ausführung werden diese Befehle praktisch in out ausgegeben. Dies ist aber für euch nicht sichtbar, da dies Anweisungen an den Browser sind. Die Anpassungen sind nur in diesem Notebook aktiv und können durch löschen der Ausgabe wieder deaktiviert werden.
Bitte beachten: Diese Einstellungen sind bisher nur bei meinem PC getestet, das Ergebnis kann auf anderen Systemen abweichen. Solltet ihr bereits (wichtige) Änderungen hier im Notebook gemacht haben, macht auf jeden Fall eine Sicherheitskopie, bevor ihr das Design das erste Mal aktiviert, da im schlimmsten (aber unwahrscheinlichen) Fall die Ausgabe nicht mehr gelöscht werden kann.
Zum Aktivieren wählt einfach die Codezelle aus und führt diese mit Strg + Enter aus.
Nach dem Aktivieren ist ein Neustart des Notebooks empfohlen, damit alle Änderungen übernommen werden (Einfach mit Strg + s speichern und mit F5 die Seite neu laden)
Zum Deaktivieren des Designs wählt ihr einfach wieder die Codezelle an und wählt oben im Menü Cell -> Current Outputs -> Clear
Sollte dies nicht funktionieren, können über Cell -> All Outputs -> Clear alle Ausgaben gelöscht werden.
Nach dem Deaktivieren ist ein Neustart des Notebooks empfohlen, damit alle Änderungen übernommen werden (Einfach mit Strg + s speichern und mit F5 die Seite neu laden)
%%html
<style>
div.cell.text_cell {
padding-top: 15px;
padding-bottom: 15px;
}
div.cell.code_cell {
padding-top: 15px;
padding-bottom: 15px;
}
.rendered_html h2 {
font-size: 200%;
padding-top: 23pt;
padding-bottom: 10pt;
}
.rendered_html h3 {
font-size: 170%;
padding-top: 8pt;
padding-bottom: 5pt;
}
.rendered_html h4 {
font-size: 140%;
}
.CodeMirror {
font-size:14px;
line-height: 25px;
}
div#notebook {
font-size: 15px;
line-height: 25px;
}
</style>
Einfachster Ablauf: Wir geben einen Befehl in Python ein. Dieser wird vom Computer ausgeführt und gibt uns (manchmal) etwas aus.
Diese einfachste Form läuft Streng nach dem Prinzip: Eingabe - Verarbeitung - Ausgabe
Wir geben 1 + 1 ein - der Computer rechnet - Es wird uns 2 ausgegeben.
1 + 1
Allgemeiner Hinweis zu Jupyter: Dies hier ist ein Textfeld, es dient nur zur Information. Alle Felder, bei denen ein In davorsteht (auch Zelle genannt), enthalten Programmcode und können ausgeführt werden. Dazu einfach eine Zelle anklicken und Strg + Enter drücken. Die Ausgabe des Programms wird dann darunter in Out angezeigt. Ihr könnt und solltet auch den Inhalt von In beliebig verändern, um das Programm anzupassen und ein wenig die Möglichkeiten auszuprobieren. Mit Strg + Enter könnt ihr dann den Code neu ausführen und die Veränderungen beobachten.
Was ist oben geschehen? In In haben wir unseren Befehl eingegeben. In diesem Fall soll uns der Computer 1 + 1 berechnen. Wenn wir die Zeile In markieren und Strg + Enter drücken, wird der Befehl ausgeführt und die Ausgabe (das Ergebnis in diesem Fall) wird in Out geschrieben.
# Hallo, ich bin ein Kommentar, ich werde nicht als Befehl gesehen und nicht ausgeführt.
# Dieses Feld hat daher keine Ausgabe, Out wird nicht erscheinen
1 +1 # Programmcode vor der Raute wird normal ausgeführt.
Kommentare in Programmen diesen dazu, anderen Menschen mitzuteilen, was man sich bei dem jeweiligen Programm/Codeteil gedacht hat und enthalten oft auch Hinweise zu Autoren, Versionen und Lizenzen. In den verschiedenen Programmiersprachen gibt es auch verschiedene Zeichen, die einen Kommentar einleiten. In Python dient die Raute (#) dazu, einen einzeiligen Kommentar einzuleiten. Alles auf der jeweiligen Zeile nach # wird als Kommentar gesehen und hat wird nicht als Befehl ausgeführt.
Ich bin auch als Kommentar gedacht, aber bei mir hat man die Raute vergessen.
Die Ausführung von mir erzeugt einen Fehler, da ich ja kein korrekter Pythoncode bin.
Die Addition haben wir ja schon kennengelernt. Wenn wir Python ohne irgendwas anderes einfach eine Rechenaufgabe geben, bekommen wir das Ergebnis ausgegeben. Es gibt aber natürlich auch andere Rechenarten als Addition in Python.
# Addition
36 + 6
# Subtraktion
9 - 4
# Multiplikation
5 * 3
# Division
5 / 2
# Ganzzahlendivision
5 // 2
# Modulo (Restdivision)
# Wichtig für Bestimmung von gerade/ungerade. Wenn x % 2 ist 0 -> x gerade, wenn x % 2 ist 1 -> x ungerade
5 % 2
# Potenz (das Erste hoch das Zweite)
2 ** 8
In Python gelten die grundlegenden Rechenregeln (Punkrechnung vor Strichrechnung).
Wir können genau wie in der Mathematik Klammern setzen.
5 + 2 * 3
(5 + 2) * 3
Bisher haben wir nur einzelne Rechenaufgaben ausgeführt und uns das Ergebnis ausgeben lassen. Wenn wir allerdings das Ergebnis einer Zahl später noch verwenden möchten, müssen wir diese (zwischen)speichern.
Dies machen wir mit sogenannten Variablen.
# Variable x wird Wert 5 zugewiesen
x = 5
Was haben wir wir gerade gemacht? Wir haben der Variable x die ganze Zahl 5 mit einen = zugewiesen. Wir werden uns im Folgenden erstmal fast ausschließlich mit ganzen Zahlen beschäftigen, um erstmal die Basics zu verinnerlichen. Es gibt allerdings noch einige weitere Typen von Daten, die wir einer Variable zuweisen können, wie zum Beispiel Text. Mit den anderen Datentypen werden wir uns später noch beschäftigen.
Eine Variable kann man sich wie eine Art Karton für Daten vorstellen. Jede Variable benötigt einen Namen. Dies ist das eindeutige Erkennungszeichen dieser Variable. Wenn wir später auch unsere gespeicherte 5 zurückgreifen möchten, müssen wir diesen Namen wieder angeben.
# Ausgabe von Variable x, vorher Zuweisung ausführen
x
Durch die Angabe des Variablennamens können wir wieder auf den Wert zurückgreifen. Dazu muss dieser aber erst durch den Befehl oben zugewiesen werden.
Variablennamen müssen mit einem Buchstaben beginnen. Bei Variablennamen, die mit z.B. einer Zahl, +, -, ... beginnen kommt Python durcheinander, da eine Zahl und andere Zeichen für (Rechen)operationen genutzt werden. Zahlen in der Mitte oder am Ende sind dabei erlaubt.
Aus Vorlesung 11:
"Variablenamen dürfen a-z
, A-Z
, 0-9
und einige Sonderzeichen (_
) enthalten. Variablennamen müssen mit einem Buchstaben beginnen.
In Python gibt es reservierte Schlüsselwörter. Diese können nicht als Variablennamen verwendet werden. Dazu gehören u.a.
and, as, assert, break, class, continue, def, del, elif, else, except, exec, finally, for, from, global, if, import, in, is, lambda, not, or, pass, print, raise, return, try, while, with, yield"
# FALSCH
1x = 5
# FALSCH
and = 5
# Richtig
x1 = 5
Variablen werden in Python, sowie in anderen Programmiersprachen flüchtig gespeichert. Das bedeutet, wenn wir Jupyter beenden und dieses Notebook neu öffnen ist unser x weg.
Die Daten von Variablen werden nicht fest gespeichert. Bei der "normalen" Ausführung von Programmen/Skripten ist das nochmal ein klein wenig anders, aber das ist an dieser Stelle für uns egal.
Wenn ihr oben auf den Menüpunkt Kernal -> Restart klickt, startet ihr die Python-Sitzung neu, die dafür sorgt, dass die Befehle hier im Notebook ausgeführt werden. Dies löscht damit gleichzeitig alle Variablen. Beachtet auch, dass die Ausgaben von Befehlen im Notebook gespeichert werden und erst erneuter Ausführung des jeweiligen Felds erneuert. Dies hat allerdings keine Auswirkungen auf die Ausführung.
Ihr könnt gerne mal probieren, Variable x oben den Wert 5 zuzuweisen, danach den Kernal neu zu starten und dann x auszugeben. Es wird ein Fehler erscheinen, da x nicht (mehr) definiert ist.
Wenn wir unsere Variablen nutzen möchten, nennen wir sie einfach, wie normale Zahlen. Python rechnet dann mit dem Wert der Variable
x = 10
x + 5
y = x - 3
y
Machen wir mal einen Test. Beachtet die Ausgabe der folgenden Befehle ...
5 + 1
4 + 9
... und die Ausgabe dieser (eigentlich identischen) Befehle:
5 + 1
4 + 9
Python gibt uns nur das Ergebnis des letzten Befehls aus. Sowieso ist die Vorgehensweise, einfach das Ergebnis von irgendwas auszugeben recht speziell für Python. Im Normalfall möchte ich ja vielleicht auch nicht, dass dem Nutzer alles mögliche Ausgegeben wird. Wir müssen dem Computer meist explizit sagen, dass er etwas bestimmtes ausgeben soll. Die passiert in Python mit einer sogenannten Funktion. Aber dazu gleich mehr.
Ein Programm in Python (sowie in anderen Programmiersprachen) wird grundsätzlich von oben nach unten gelesen, genauso, wie wir auch als Menschen ein Buch lesen würden.
Dabei müssen wir jeden Befehl in einer eigenen Zeile schreiben.
Zuerst wird der Befehl in der ersten Zeile ausgeführt, dann der in der zweiten, usw.. Ich kann also nicht in der ersten Zeile den Wert von x ausgeben lassen, wenn x erst in der zweiten Zeile einen Wert zugewiesen bekommt.
Eine Funktion muss man sich wie ein kleines Unterprogramm vorstellen. Wir können uns diese Funktionen selber schreiben, oder auf vordefinierte zurückgreifen, die uns Python zur Verfügung stellt.
Eine Funktion können wir aufrufen, indem wir den Namen der Funktion nennen und dann in Klammern der Funktion Werte (Parameter) übergeben, mit der die Funktion dann ihre jeweilige Aufgabe erledigt.
x = 5 + 4
# Mit print können wir Dinge ausgeben. Dabei müssen wir in Klammern schreiben, was wir ausgeben möchten.
print(x)
x = 42
print(x)
print(10)
An diesem Beispiel kann auch nochmal gut erläutert werden, was in Python nacheinander passiert:
Durch sogenannte Module haben wir Zugriff auf eine Vielzahl von vordefinierten Funktionen. Damit wir auf die Funktionalität (Symbole) eines bestimmten Moduls zugreifen können, müssen wir dieses ersmal importieren. Dazu schreibe ich einfach den Befehl import und dahinter den Namen des Moduls, das wir haben möchten.
import math
Das wars schon. Nun können wir nach Herzenslust auf das Modul math zufreifen, welches uns eine Vielzahl von mathematischen Funktionen bereitstellt. Um jetzt darauf zugreifen zu können schreibe ich den Namen des Moduls, dahinter einen Punkt und dann die gewünschte Funktionalität.
# math.pi gibt mir die Kreiszahl pi
print(math.pi)
# Sinus, Cosinus und Tangens
print(math.sin(120))
print(math.cos(120))
print(math.tan(120))
Wir können uns jetzt noch eine alternative Importmethode anschauen, die uns das ständige schreiben des Modulnamens vor unserer gewünschten Funktionalität erspart.
# wir importieren damit alle (*) Funktionalitäten (Symbole) von math in unseren globalen Namensraum
from math import *
# jetzt können wir ohne Modulnamen aufrufen
print(pi)
# Sinus, Cosinus und Tangens
print(sin(120))
print(cos(120))
print(tan(120))
# wir importieren damit die benötigten Funktionalitäten (Symbole) von math in unseren globalen Namensraum
from math import pi, sin, cos, tan
# jetzt können wir ohne Modulnamen aufrufen
print(pi)
# Sinus, Cosinus und Tangens
print(sin(120))
print(cos(120))
print(tan(120))
Die print() Funktion kann und etwas auf dem Bildschirm anzeigen. Allerdings hat darf man das nicht mit einem Rückgabewert verwechseln. Die Ausgabe von print() ist kein Rückgabewert.
Ein Rückgabewert ist ein Wert, welchen eine Funktion - wie der Name schon sagt - zurückgibt. Dieser wird dem Nutzer (bei mehrzeiligen Programmen) nicht ausgegeben. Er dient uns zur weiteren Verarbeitung, indem wir ihn in einer Variable speichern, oder als Parameter an eine weitere Funktion geben.
Wir können den Rückgabewert im Grunde wie eine normale Zahl einer Variable zuweisen, also Variablenname = Funktionsname(Parameter). Dabei wird die Funktion Funktionsname aufgerufen und der Rückgabewert in die Variable Variablenname gespeichert.
Machen wir mal einen Versuch:
# wir holen uns die Funktion sin() von math
from math import sin
# Funktion print() wird aufgerufen und Rückgabewert in x gespeichert.
x = print("Hallo")
# Funktion sin() wird aufgerufen und Rückgabewert in x gespeichert.
y = sin(42)
Wir haben nun die Funktionen print() und sin() aufgerufen und die Rückgabewerte jeweils x und y zugewiesen.
Das Hallo, welches wir print übergeben haben, wurde uns sofort ausgegen, denn genau das macht die Funktion print(). Das Hallo ist aber nicht der Rückgabewert von print. Dieser ist unabhängig von dem ausgegebenen Text und wurde stillschweigend in Variable x gespeichert.
Die Funktion sin() hat uns nichts auf dem Bildschirm ausgegeben. Das ist auch richtig so, da sin() ja nicht wie print() ein Befehl zur Ausgabe ist, sondern uns den Sinus des übergebenen Werts - in diesem Fall 42 - ermitteln soll. Dies hat sin() auch gemacht und diesen - auch wieder stillschweigend - als Rückgabewert in y gespeichert.
Schauen wir uns nun die Werte von x und y einmal an.
# Rückgabewert von sin(42)
y
Hier ist alles korrekt verlaufen. Der Rückgabewert von der sin() Funktion wurde korrekt der Variable y zugewiesen. Schauen wir uns jetzt an, was print() uns zurückgegeben hat.
# Rückgabewert von print("Hallo")
x
Die Ausgabe ist leer! Dies bedeutet, es gab keinen Rückgabewert beim Aufruf von print("Hallo"). Daran ist auch nichts falsch. Bei sin() möchten wir einen Rückgabewert, denn wenn wir den Sinus berechnen, wollen wir natürlich auch, dass wir einen Wert bekommen, den wir einer Variable zuweisen können, um ihr später in weiteren Berechnungen einsetzen zu könnnen. Wir möchten aber nicht, dass dieser dem Nutzer auf dem Bildschirm ausgegeben wird. Man stelle sich einmal vor, wir würden bei jedem Programm, das wir starten, jede Zwischenrechnung ausgegeben bekommen. Das möchten wir natürlich nicht. Wenn wir etwas ausgeben möchten, haben wir dafür die Funktion print().
Jetzt, da wir das nötige Handwerkszeug haben, um Funktionen aufzurufen, können wir auch anfangen, unsere eigenen Funktionen zu erstellen.
Diese Definitionen haben folgende Struktur: Zuerst kommt das Schlüsselwort def. Dahinter schreiben wir den Namen der Funktion, mit dem wir diese später auch aufrufen können. Danach werden in Klammer die sogenannten Parameter aufgezählt, jeweils getrennt durch ein Komma. Parameter sind Variablen, denen wir beim Aufruf der Funktion einen Wert zuweisen. Diese sind nur innerhalb des Aufrufs der Funktion gültig. Parameter sind allerdings nicht unbedingt notwenig, um eine Funktion zu definieren. Wenn wir keine Parameter haben (wollen), müssen wir aber trotzdem () schreiben, um eine leere Liste an Parametern zu signalisieren. Das ganze wird mit einem Doppelpunkt abgeschlossen. Jetzt brauchen wir nur noch ein paar Befehle, die wir innerhalb der Funktion ausführen wollen. Diese müssen eingerückt werden. Das bedeutet, wir müssen die Befehle mit 4 Leerzeichen oder besser einem Tabulator (Taste neben q) nach rechts rücken. Meist passiert das schon automatisch, wenn wir mit Enter nach dem Doppelpunkt eine neue Zeile anfangen. Diese Verschiebung signalisiert, dass diese Befehle zu dem Konstrukt Funktion gehören, das wir durch den Doppelpunkt eingeleitet haben. Wenn wir fertig sind mit unsere Funktion, schreiben wir normal ganz links weiter. Damit kann Python erkennen, dass wir mit dem Funktionsblock fertig sind.
def hallowelt():
print("Hallo")
print("Welt")
print("Unsere Erste Funktion ist definiert!")
Damit haben wir schon unsere erste Funktion definiert, die den Namen hallowelt trägt, keine Parameter bekommt und eine Zeile Hallo und eine Zeile Welt ausgibt. Wir können sie jetzt wie wir es bereits gewohnt sind, ausführen.
hallowelt()
Fügen wir jetzt noch einen Parameter hinzu.
def hallowelt(a):
print("Hallo")
print("Welt")
print(a)
hallowelt(42)
... und gleich noch einen.
def hallowelt(a,b):
print("Hallo")
print("Welt")
print(a)
print(b)
hallowelt(42, 24)
Eine weitere tolle Sache, die Funktionen können, ist einen Wert zurückgeben. Diesen zurückgegebenen Wert kann zum Beispiel einer Variable zuweisen. Mit dem Schlüsselwort return, gefolgt von dem Wert, den ich zurückgeben möchte, beendet die aktuelle Ausführung der Funktion und liefert mir den Rückgabewert.
def einsmehr(a):
return a + 1
x = einsmehr(41)
print(x)
Es ist wichtig, dass wir uns den Unterschied zwischen Variablen und Funktionen einprägen.
Variablen dienen uns als Speicher für Daten, während Funktionen als eine Art Unterprogramme gesehen werden können, die ich definieren - also festlegen - und danach aufrufen kann.
Sinnbildlich gesprochen kann man z.B. Microsoft Word als Funktion und das Worddokument (.doc Datei) als Variable sehen.
Da ich beide definiere und ihnen einen Namen zuweise, kann dies am Anfang sehr verwirrend sein und zu Verwechslungen führen. Daher ist es wichtig, sich die Formate von Variablen und Funktionen einzuprägen, wie zum Beispiel die Klammern () nach dem Namen, an denen wir Funktionen erkennnen.
Wir haben jetzt alles behandelt, was notwendig ist, um uns der ersten Aufgabe von Praktikum 11 zu widmen. Dazu müssen wir erstmal die Testfunktion importieren und testen. Die unten stehende Zeile müssen wir dabei nur einmal bei jedem Öffnen des Notebooks ausführen. Die Ausgabe des folgenden sollte "Die Lösung ist korrekt :)" sein
# Diese Zelle bitte einmalig ausführen!
from hsmwgk.test import test
def die_antwort():
return 42
# Die letzte Zeile nicht löschen
# Diese prüft, ob die Lösung stimmt!!!
test(die_antwort)
Aufgabe 1
Schreiben Sie die Funktion add
.
Diese akzeptiert zwei Zahlen und gibt deren Summe zurück.
Folgende Überlegungen können wir anstellen: Wir müssen eine Funktion definieren, die add heißt. Also schreiben wir erstmal das Schlüsselwort def und dahinter den Namen der Funktion, also add. Nun müssen wir noch in Klammern festlegen, welche Parameter wir haben wollen. Da wir 2 Zahlen akzeptieren sollen, brauchen wir 2 Parameter. Die Namen können wir frei wählen. Nennen wir sie einfach z1 und z2. Machen wir die Klammer wieder zu und schließen die Zeile mit Doppelpunkt ab.
Danach müssen wir eingerückt unseren Code eingeben. Wir sollen die Summe beider Zahlen bestimmen. Daher definiere ich jetzt die Variable ergebnis und weise ihr einen Wert zu, und zwar z1 + z2.
Jetzt sind wir auch schon fast fertig. An dieser Stelle wird schon das richtige Ergebnis bestimmt, das Problem ist nur, dass die Funktion einfach beendet werden würde, ohne, dass ein Ergebnis zurückgegeben wird. Also schreiben wir noch return und sagen dahinter, was wir den zurückgeben möchten, und zwar den Wert von Variable ergebnis.
Zum Schluss rufen wir noch die Funktion test auf und übergebe ihr den Funktionsnamen und erhalte beim Ausführen die Meldung "Die Lösung ist korrekt :)"
def add(z1, z2):
ergebnis = z1 + z2
return ergebnis
test(add)
Es gibt noch eine bessere und kürzere Lösung. Zwar ist es erstmal übersichtlicher, das Ergebnis in eine Variable zu speichern und dann auszugeben, allerdings ist dies nicht notwendig. Wir können auch gleich dem return sagen, dass es z1 + z2 ausgeben soll.
def add(z1, z2):
return z1 + z2
test(add)
Bisher hatten wir es (fast) nur mit ganzen Zahlen zu tun gehabt. Python kann aber auch noch mehr. Es gibt noch weitere Typen von Daten mit denen wir umgehen können und die wir in Variablen speichern können. Im Folgenden schauen wir uns verschiedene Datentypen an und lernen, mit ihnen umzugehen.
Mit der Funktion type() können wir uns den Datentyp von einem uns übergebenen Wert bestimmen lassen.
# Ganze Zahl (Integer)
type(5)
# Gleitkommazahl (Float)
type(4.2)
# Wahrheitswert (Boolean)
type(True)
# Zeichenkette (String)
type("Hallo, ich bin ein Text")
Diesen Typ haben wir bereits zu Genüge kennengelernt. Integer sind ganze Zahlen ohne Komma, mit denen wir rechnen können. Diese könen auch negativ sein (siehe Beispiel).
# Auch negative Werte sind möglich
type(-3)
Mit diesen verhält es sich ähnlich, wie mit den Ganzen Zahlen, nur dass diese eben nicht ganz sind. ACHTUNG: Als "Komma" dient uns hierbei der Punkt. Auch Float kann negativ sein.
type(3.14)
# FALSCH
type(3,14)
Bei den Wahrheitswerten gibt es nur 2 mögliche Werte. True (Wahr, 1, Strom fließt) und False (Falsch, 0, Strom fließt nicht)
Bitte beachtet hierbei, dass am Anfang groß und dann klein weiter geschrieben werden muss.
type(False)
Zeichenketten ist eine Aneinanderreihung von Zeichen beliebiger Länge. Kurz gesagt: Text
Wenn wir eine Zeichenkette definieren, müssen wir darauf achten, dass wir mit " beginnen und enden.
type("Ich bin eine Zeichenkette")
# FALSCH
type (Ich soll auch eine Zeichenkette sein, aber bei mir wurden die Anführungsstriche vergessen)
Möchten wir z.B. eine ganze Zahl in eine Gleitkommazahl oder umgedreht oder eine Zahl in eine Zeichenkette umwandeln, ist dies in Python recht einfach.
Wir haben für jeden Datentyp eine eigene Funktion, die wir mit unserem Wert füttern und bekommen ihn im jeweiligen Format als Rückgabewert zurück.
x = 5
print("x:", x, type(x))
# Integer wird in Float verwandelt
y = float(x)
print("y:", y, type(y))
Im Grunde kann ich (fast) alles in (fast) alles umwandeln. Ich muss nur darauf achten, dass sich die übergebenen Daten auch wirklich im gewünschten Format logisch interpretieren lassen. Dazu ein paar Beispiele:
# Da wir wahr oder falsch auch als 0 oder 1 ausdrücken können, ist folgende Umwandlung möglich
x = 0
print(bool(x))
x = 1
print(bool(x))
# Sofern eine Zeichenkette gültige Zahlen enthält, können wir diese in Integer/Float umwandeln
x = "5"
y = int(x)
print(type(y))
Eine 2 ließe sich zum Beispiel nicht in Boolean umwandeln, der Versuch würde zu einer Fehlermeldung führen (Ihr könnt es ja gerne mal ausprobieren).
An dieser Stelle können wir uns bereits der ersten Aufgabe mit Strings wenden. Zuerst wieder der Import.
# Diese Zelle bitte einmalig ausführen!
from hsmwgk.test import test
def die_antwort():
return 42
# Die letzte Zeile nicht löschen
# Diese prüft, ob die Lösung stimmt!!!
test(die_antwort)
# WICHTIG: Die Ausgabe sollte hier "Die Lösung ist korrekt :)" sein.
Aufgabe 1
Schreiben Sie die Funktion buchstabe_a
.
Dieser Funktion wird ein String übergeben.
Geben Sie die Anzahl aller A
(Groß und Klein!) zurück.
Da nur ein String übergeben wird definieren wir erstmal die Funktion buchstabe_a mit einem Parameter und nennen ihn eingabe.
Nun gibt es verschiedene Lösungen.
Auf jeden Fall benötigen wir die Funktion count, die uns ein bestimmtes Zeichen zählt. Nun können wir schon mal mit eingabe.count("a") die kleinen a zählen. Jetzt sind wir allerdings noch nicht fertig. Die großen A fehlen noch. Also sagen wir ganz einfach mit + eingabe.count("A"), dass die großen A dazugezählt werden.
Das ganze schreiben wir natürlich wieder hinter ein return, um Python zu sagen, dass das zurückgegeben werden muss.
def buchstabe_a(eingabe):
return eingabe.count("a") + eingabe.count("A")
test(buchstabe_a)
Wie so oft gibt es mehrere mögliche Lösungen. Wir können uns auch eines Tricks bedienen und erstmal mit upper() oder lower() alle Buchstaben von eingabe klein oder groß machen. Dann müssen wir nur noch einmal mit count() zählen, da dann jedes große A in ein kleines a verwandelt wird oder umgekehrt.
def buchstabe_a(eingabe):
umgewandelt = eingabe.lower()
return umgewandelt.count("a")
test(buchstabe_a)
Das geht noch ein wenig eleganter. Auch hier müssen wir nicht unbedingt erst wieder in eine Variable zwischenspeichern. eingabe.lower() führt die Funktion lower() auf der Variable eingabe aus, um diese umzuwandeln. Das hat uns einen String zurückgegeben, den wir wieder in der Variable mit dem Namen "umgewandelt" gespeichert haben, zur weiteren Verarbeitung mit count(). Allerdings können wir, da uns lower() wieder einen String gegeben hat, direkt nach der Funktion normal wie bei einer Variable weitermachen, das bedeutet wir können das ganze auch gleich danach weiter verarbeiten mit der count() Funktion.
def buchstabe_a(eingabe):
return eingabe.lower().count("a")
test(buchstabe_a)
Weiter oben habe ich euch erzählt, dass jeder Befehl von oben nach unten der Reihe nach ausgeführt wird.
Nunja, im Grunde ist dies nicht zwingendermaßen so. Python und andere Programmiersprachen bieten uns die Möglichkeit, bestimmte Teile unseres Programms nur bestimmten Bedingungen auszuführen, oder auch unter bestimmten Bedingungen zu wiederholen.
Auch haben wir schon die Möglichkeit kennen gelernt, Funktionen zu definieren, dessen Inhalt erst ausgeführt wird, wenn wir sie mit Funktionsname(Parameter) aufrufen. Diese grenzen sich aber von den hier vorgestellten bedingten Ausführungen und Wiederholungen ab.
Dies sind Konstrukte, die nur unter bestimmten (logischen) Bedingungen ausgeführt werden. Dies setzt voraus, dass wir eine bestimmte Bedingung definieren können. Diese müssen mit einem Wahrheitswert (wahr oder falsch) beantwortbar sein.
Hier ein Beispiel:
# Das Ergebnis der logischen Bedingung 5 < 3 wird ausgegeben
print(5 < 3)
# Der Datentyp der
print(type(5 < 3))
Im oberen Beispiel lassen wir uns 5 < 3 ausgeben. Dies erkennt Python als eine Aussage, also eine Behauptung. Diese ist korrekt formuliert, obwohl es eine falsche Aussage ist. Aus diesem Grund wird diese auch von Python beantwortet, und zwar mit False (Falsche Aussage).
Es verhält sich praktisch ähnlich, wie mit den Rückgabewerten von Funktionen. Wenn wir eine Behauptung schreiben, bekommen wir die Antwort in Form von Wahr oder Falsch als Boolean zurück.
Vergleichsoperatoren spielen eine entscheidende Rolle bei Aussagen. Diese kennen wir bereits aus der Mathematik. Mit ihnen können wir Aussagen formen, die sich eindeutig und logisch mit wahr oder falsch beantworten lassen.
x = 10
y = 20
# Ergibt True, wenn x kleiner ist als y
print(x < y)
# Ergibt True, wenn x größer ist als y
print(x > y)
# Ergibt True, wenn x den gleichen Wert hat, wie y
# Nicht zu verwechseln mit = (Weist Variable Wert zu)
print(x == y)
# Ergibt True, wenn x nicht gleichen Wert hat, wie y
print(x != y)
# Ergibt True, wenn x kleiner ist als y oder den gleichen Wert hat
print(x <= y)
# Ergibt True, wenn x größer ist als y oder den gleichen Wert hat
print(x >= y)
Mit dem Wort not vor einem Wahrheitswert können wir diesen auch negieren (aus wahr wird falsch, aus falsch wird wahr)
x = 10
y = 20
# Das Gegenteil von -> Ergibt True, wenn x kleiner ist als y
print(not x < y)
# Das Gegenteil von -> Ergibt True, wenn x größer ist als y
print(not x > y)
# Das Gegenteil von -> Ergibt True, wenn x den gleichen Wert hat, wie y
print(not x == y)
# Das Gegenteil von -> Ergibt True, wenn x nicht gleichen Wert hat, wie y
print(not x != y)
# Das Gegenteil von -> Ergibt True, wenn x kleiner ist als y oder den gleichen Wert hat
print(not x <= y)
# Das Gegenteil von -> Ergibt True, wenn x größer ist als y oder den gleichen Wert hat
print(not x >= y)
COMING SOON
Da wir nun genug über die Formulierung von Aussagen wissen, können wir nun damit beginnen, unsere Programme damit dynamischer auszuführen.
Mithilfe von Bedingungen haben wir die Möglichkeit, bestimmte Teile des Codes nur unter bestimmten Voraussetzungen auszuführen.
Dies folgt einem einfachen Muster: Zuerst sagen wir mit dem Schlüsselwort if, dass wir eine bedingte Ausführung einleiten. Danach geben wir einen Wahrheitswert an - meist durch eine Aussage - und beenden die Zeile mit einem Doppelpunkt. Danach müssen wir natürlich auch noch festlegen, welche der nachfolgenden Befehle von dieser Bedingung abhängig sind. Dies lösen wir mit Einrückung der Befehle, entweder mit 4 Leerzeicher, oder besser mit einem Tabulator (Taste links neben q). Dies passiert in Jupyter Lab oft automatisch. Alle so eingerückten Befehle - auch Block genannt - werden nur unter der oben definierten if Bedingung ausgeführt.
print("Hier gehts ganz normal los")
# Der folgende Block wird ausgeführt, da Wahr übergeben wird
if True:
print("Bedingung mit True")
print("Noch eine Zeile im Block")
print("Hier gehts normal weiter")
# Der folgende Block wird NICHT ausgeführt, da Falsch übergeben wird
# Alle eingerückten Befehle werden übersprungen
if False:
print("Bedingung mit False")
print("Noch eine weitere Zeile im Block")
print("Ende")
Wir können den Wahrheitswert für die if-Bedinung auch aus Variablen nehmen
x = True
print("x wurde auf True gesetzt")
# Wird ausgeführt, da wir x als True, also wahr definiert haben
if x:
print("x ist wahr")
x = False
print("x wurde auf False gesetzt")
# Wird nicht ausgegeben, da die Bedingung falsch ist
if x:
print("x ist immernoch wahr")
# Durch die Negation von False, wird True daraus, also wieder wahr
if not x:
print("x ist nicht wahr")
Das Ganze lässt sich natürlich auch mit den oben behandelten Vergleichsoperatoren dynamisch gestalten. Dies ist ja letztendlich unsere Motivation.
x = 25
if x > 20:
print ("x ist größer als 20")
if x < 10:
print("x ist kleiner als 10")
Wir können auch noch weiter verschachteln. Innerhalb eines Blocks können wir noch einen weiteren Block erstellen, also eine weitere Bedingung. Diese muss eine Stufe weiter eingerückt werden.
x = 26
if x > 20:
print("x ist größer als 20")
# Da hier schon die Einrückung des vorherigen if,
# wird das nächste if nur betrachtet, wenn das vorherige
# wahr ist, wir also in den eingerückten Block gewandert sind.
if x > 25:
print("... und sogar größer als 25")
print("Sagenhaft!")
print("Hier könnte Ihre Werbung stehen!")
print("Ende des Programms")
Nach einem if haben wir noch zwei weitere optionale Möglichkeiten. Wir können noch ein elif (else if) oder else definieren.
Ein elif folgt den selben Regeln, wie ein normales if, mit dem Unterschied, dass dieses nur geprüft wird, wenn das davor stehende if - oder elif - falsch war. War es richtig, wird dieses elif - und alle weiteren eventuell folgenden elif und else - ohne Prüfung übersprungen.
Ein else muss nach einem if - oder einer Kette von if und elif - stehen und wird nur dann ausgeführt, wenn keines der vorherigen if oder elif Anweisungen der jeweiligen Verkettung wahr war. Ein else enthält deshalb auch keine Aussage, wie if oder elif.
x = 25
if x > 20:
print("x ist größer als 20")
else:
print("x ist nicht größer als 20")
x = 18
if x > 20:
print("x ist größer als 20")
elif x > 15:
print("x ist größer als 15")
elif x >= 10:
print("x ist größer oder gleich 10")
x = 4
if x > 20:
print("x ist größer als 20")
elif x > 15:
print("x ist größer als 15")
elif x >= 10:
print("x ist größer oder gleich 10")
else:
print("x ist kleiner als 10")
x = 25
# Die Folgenden if sind nicht verkettet, da kein if anstatt elif
if x > 20:
print("x ist größer als 20")
if x > 15:
print("x ist größer als 15")
if x >= 10:
print("x ist größer oder gleich 10")
Eine while-Schleife ist einer if-Bedingung ganz ähnlich - mit dem Unterschied, dass die Anweisungen des Blocks wiederholt ausgeführt werden, solange die Bedinung wahr ist.
Am Anfang ist das Vorgehen der while-Schleife identisch mit der if-Bedingung. Wenn die Aussage wahr ergibt wird ausgeführt, ansonsten übersprungen. Am Ende des Blocks, nach der Ausführung geht es allerdings nicht normal im Programm weiter, sondern es wird nochmals geprüft, ob die Aussage der Schleife immernoch wahr ist. Wenn dies der Fall ist, wird der Block nochmal ausgeführt. Das geht so lange weiter, bis die Bedingung am Ende einer Ausführung des Blocks nicht mehr wahr ist.
Hierbei muss man auch aufpassen, da man bei fehlerhaften Skripten eine Endlosschleife erzeugen kann. Dabei wird die Bedingung am Ende des Blocks nie falsch und dieser wird dann ohne Ende ausgeführt.
x = 10
while x > 0:
print(x)
x = x - 1
Die while Schleife von oben liest sich praktisch folgendermaßen:
Solange x größer als 0, mache: gib x aus verringere x um 1
Hierbei ist wieder zu beachten, dass man x = x - 1 schreibt und NICHT x - 1. Die falsche Variante würde zwar auch 1 von x abziehen, aber den neuen Wert nicht wieder in x speichern, x würde sich also nie verändern und wir würden eine Endlosschleife erzeugen. Das Programm würde dann endlos lange die 10 ausgeben. Sollte uns so etwas mal passieren, hilft ein klick auf den Stopp-Button (schwarzes Rechteck) oder der Menüpunkt Kernel -> Interrupt. Dies stoppt die Ausführung.
Jetzt geht es ein wenig ans Eingemachte, was Datentypen anbelangt. Wir beschäftigen uns mit Strings und Listen. Kleiner Spoiler: So unterschiedlich sind diese beiden Datentypen im Grunde nicht.
Aber erstmal müssen wir ein wenig tiefer in das Thema Datentypen eintauchen und die Frage klären, warum die Unterscheidung verschiedener Datentypen so wichtig ist. Schauen wir uns erstmal dieses Beispiel an:
x = 1
y = "1"
print("Datentyp von x:", type(x))
print("Datentyp von y:", type(y))
Sowohl x, als auch y haben wir die Zahl 1 zugewiesen, mit dem Unterschied, dass wir die 1 in y zwischen " gesetzt haben. Die Anführungsstriche sind praktisch das Erkennungszeichen von Strings.
Aber warum ist dieser Unterschied so entscheidend?
Schauen wir uns einmal dieses Negativbeispiel an:
# Gibt uns einen Fehler aus
x = 1
y = "1"
x + y
Seltsam. Obwohl doch beide Variablen eine Zahl, und zwar die 1 enthalten, kann ich sie nicht addieren.
Das liegt daran, dass die 1 in y keine Zahl ist, sondern ein Zeichen. Klingt zwar erstmal komisch, aber aus vorherigen Vorlesungen wissen wir:
Der Computer kennt nur 1 und 0 (Binär). Nur diese zwei Zustände sind ihm bekannt und damit müssen wir auch alles ausdrücken können (Zahlen, Texte, Farben,...). Dies bedeutet, wenn ich eine bestimmte Kombination daraus hernehme, zum Beispiel 1010111, oder auch jede beliebige andere Kombination jeder anderen Länge, könnte dies eine Zahl sein, mit der ich auch ähnlich rechnen kann, wie mit einer normalen Dezimalzahl.
Es könnte aber auch sein, dass dies ein bestimmtes Zeichen im ASCII-Code ist. Mit diesem kann der Computer Zeichen darstellen, da die 7 Bit im einfachen ASCII-Code 128 verschiedene Kombinationsmöglichkeiten besitzen. Jeder dieser Möglichkeiten ist ein anderes Zeichen zugeordnet und somit kann der Computer die gespeicherten Einsen und Nullen in Zeichen umwandeln, die uns als Text dargestellt werden. Diese Einsen und Nullen kann ich zwar theoretisch auch Addieren, nur würde es ziemlich sinnlos sein, ein g und t zu addieren und das Ergebnis würde mir auch nichts sagen. Es sind halt Zeichen, keine Zahlen.
Dies führt dazu, dass die 1 als Zahl einfach als eine binäre Zahl - wie wir sie in vorherigen Vorlesungen und Tutorien kennengelernt haben - im Computer gespeichert ist, während die "1" als Text die Kombination aus Einsen und Nullen beinhaltet, die das Zeichen 1 im ASCII-Code darstellt. Dies ist für den Computer auch ein ganz normales Zeichen, wie auch jeder Buchstabe.
Schauen wir uns im folgenden Beispiel einmal an, wie unser Computer die 1 - sowohl als Zahl, als auch als Zeichen - sieht:
# Hier muss eine Zahl als Integer stehen
zahl = 1
# Hier muss ein String stehen.
# Kann auch mehrere Zeichen beinhalten,
# inklusive Buchstaben. (Nur ASCII-Zeichen)
text = "1"
# HINWEIS: Ab hier müsst ihr den Code nicht verstehen,
# er dient nur der anschaulichen Anzeige in binär
# und ist NICHT Teil der Übung
from re import sub
print("zahl in Binär:", bin(zahl)[2:].zfill(7))
print("text in Binär:", sub("[\[\]',]","",str([bin(ord(z))[2:].zfill(7) for z in text])))
Wir sehen also: Die 1 als Zahl (Integer) ist für den Computer etwas vollkommen anderes, als die 1 als Text (Sting).
Ihr könnt auch gerne die Zahl und den Text beliebig anpassen und euch das Ergebnis anschauen. Ihr werdet sehen, dass, wenn ihr einen Text aus zwei Zeichen eingebt, auch zwei 7er-Gruppen an Einsen und Nullen erscheinen, da ich ja bei ASCII mit 7 Bit die 128 Kombinationen für EIN Zeichen habe, die 7 Bit sind also immer pro Zeichen, wir haben also von der Sache her eine Liste an Zeichen, die mit steigender Zeichenanzahl immer mehr Bits braucht (dies wird gleich nochmal wichtig).
Bei Integer ist die Anzahl der Bits immer gleich, auch wenn die Zahl nur ein Bit bräuchte, wie bei unserer 1, wird eine feste Anzahl an Bits dafür reserviert, weshalb ein Integer auch nicht unendlich groß werden kann.
Falls sich jetzt jemand die gute Frage gestellt hat, warum ich dann einen String der Zahlen enthält in Integer umwandeln kann, möchte ich das hier auch gleich noch beantworten. Die Funktion int() ist so programmiert, dass sie die speziellen Zeichen, welche Zahlen repräsentieren ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"] im Text praktisch wieder in eine richtige Zahl verwandelt.
Aus dem vorgerigen Kapitel haben wir jetzt schon einiges über Strings erfahren und ich habe bereits etwas angedeutet: Ein String ist eine (spezielle) Liste.
Wir hatten also jetzt öfters schon mit Listen zu tun gehabt, ohne, dass uns das bewusst war.
Im Allegmeinen lässt sich eine Liste so vereinfachen: Eine Liste ist eine Form der Variable, die nicht nur einen Wert (Beispiel Integer: Wir haben genau eine Zahl pro Variable), sondern beliebig viele Werte (also zum Beispiel ganz viele Integer) enthalten kann. Die Werte in einer müssen nicht (Ausnahme: String) einen bestimmen oder den gleichen Datentyp besitzen.
Nehmen wir unseren String: Ein String ist eine Liste, welche Werte vom Datentyp Char (Zeichen) enthält. Definieren wir zum Beispiel den String "Tutorium", so ist dieser String eine Liste aus 8 Werten des Typs Char (weil 8 Zeichen lang).
Die Elemente haben eine genaue Reihenfolge. Das heißt, jedes Element - im String also jeder Buchstabe - hat eine Nummer, die die Position anzeigt. Diese Nummern beginnen bei 0. An unserem Beispiel des Strings "Tutorium" sieht das folgendermaßen aus:
Element 0: T Element 1: u Element 2: t Element 3: o Element 4: r Element 5: i Element 6: u Element 7: m
Damit uns das Ganze auch was nützt müssen wir natürlich auch die Möglichkeit haben, auf einzelne Werte/Elemente (also einzelne Zeichen) zurückgreifen können. Dies können wir bei jeder Liste mit Klammern tun. Und zwar mit eckigen Klammmern: [ und ]
Innerhalb dieser Klammer definieren wir mithilfe von Zahlen (richtige Zahlen, also Integer), welches Element wir möchten (auch Index genannt).
Bei unserem Beispiel sieht das folgendermaßen aus:
# String wird definiert
x = "Tutorium"
# 3. Zeichen (Achtung, 1. Element ist Nummer 0) von x ausgeben
print(x[2])
Wir können unseren Index - also die Nummer des Elements - auch aus einer Variable lesen lassen.
# String wird definiert
x = "Tutorium"
# Nummer des gewünschten Index
y = 2
# y. Zeichen (Achtung, 1. Element ist Nummer 0) von x ausgeben
print("Index", y)
print(x[y])
Um auf ein bestimmtes Element eines Strings zugreifen zu können, müssen wir diesen nicht einmal in eine Variable speichern (gilt auch für andere Listen). Das ganze sieht dann so aus:
# 3. Zeichen (Achtung, 1. Element ist Nummer 0) von "Tutorium" ausgeben
print("Tutorium"[2])
... oder so:
# Nummer des gewünschten Index
y = 2
# y. Zeichen (Achtung, 1. Element ist Nummer 0) von "Tutorium" ausgeben
print("Index", y)
print("Tutorium"[y])
Wir können uns auch gleich mehrere Elemente einer Liste auf einmal ausgeben lassen. Dafür schreiben wir unsere Klammern einfach in folgendem Format: [erstes Element:letzes Element]
Den Doppelpunk (:) lesen wir als "bis". Aber ACHTUNG: es ist immer "bis außschließlich" dem letzten Element verstehen, also, wenn wir schreiben 0:3 liest sich das: Element 0 bis ausschließlich 3. Das Element mit dem Index 3 ist also schon nicht mehr mit drin. Das kann zusammen mit der Tatsache, dass das erste Element den Index 0 besitz erstmal sehr verwirrend sein, also spielt erstmal ein wenig mit dem Beispiel und probiert euch durch verschiedene Werte für Start und Ende.
x = "Tutorium"
# Element 0 bis ausschließlich 3 wird ausgegeben
print(x[0:3])
Wir haben auch die Möglichkeit, ab einem gewissen Element bis zum Ende der Liste auszuwählen. Dazu schreiben wir wieder unseren Doppelpunkt, aber dahinter keine Zahl.
x = "Tutorium"
# Element 3 bis Ende wird ausgegeben
print(x[3:])
Auch gibt es eine Reihe an nützlichen Funktionen für Strings:
meinText = "Hallo Welt"
# In Kleinbuchstaben umwandeln
print("lower:", meinText.lower())
# In Großbuchstaben umwandeln
print("upper:", meinText.upper())
# Zeichenanzahl bestimmen
print("len:", len(meinText))
# Bestimmtes Zeichen (hier l) zählen
print("count (l):", meinText.count("l"))
# gibt True, wenn Zeichen Kleinbuchstabe (ACHTUNG: Nur ein Zeichen erlaubt)
print("a".islower())
# gibt True, wenn Zeichen Großbuchstabe (ACHTUNG: Nur ein Zeichen erlaubt)
print("a".isupper())
# Diese Zelle bitte einmalig ausführen!
from hsmwgk.test import test
def die_antwort():
return 42
# Die letzte Zeile nicht löschen
# Diese prüft, ob die Lösung stimmt!!!
test(die_antwort)
# WICHTIG: Die Ausgabe sollte hier "Die Lösung ist korrekt :)" sein.
Schreiben Sie die Funktion kuchen_backen
.
An diese Funktion wird je eine zufällige Zutat in Kleinbuchstaben als String übergeben. Die Funktion soll True
zurückgeben, wenn eine Zutat aus dem nachfolgenden Lied übergeben wurde:
Wer will guten Kuchen backen,\
der muss haben sieben Sachen:\
eier
und schmalz
,\
zucker
und salz
,\
milch
und mehl
,\
safran
macht den Kuchen gel!
Wir können diese Aufgabe bereits lösen. Diese Lösung ist zwar nicht die eleganteste, aber immerhin schonmal richtig. Wir werden später noch eine bessere Lösung kennenlernen.
Was müssen wir tun? Wir bekommen eine Zeichenkette als Parameter und müssen nun mit einem Wahrheitswert (True oder False) beantworten, ob diese zeichenkette in unserer Zutatenliste vorhanden ist. Wie machen wir das mit als Mensch? Wir würden uns wahrscheinlich die Zeichenkette, die uns gegeben wurde anschauen und von oben bis unten unsere Liste durchgehen. Sobald wir unsere Zutat gefunden haben können wir melden, dass die Zutat vorhanden ist (also True) und an dieser Stelle auch aufhören zu suchen. Wenn wir durch sind, aber keinen Treffer gelandet haben, können wir melden, dass die Zutat nicht in der Liste ist (also False).
Dies können wir auch unserem Computer im Grunde genau so beibringen:
def kuchen_backen(x):
if x == "eier":
return True
elif x == "schmalz":
return True
elif x == "zucker":
return True
elif x == "salz":
return True
elif x == "milch":
return True
elif x == "mehl":
return True
elif x == "safran":
return True
else:
return False
test(kuchen_backen)
Im Detail passiert folgendes:
Wir haben eine if-elif-else Kette definiert. Die liest sich: Wenn ... dann ..., sonst wenn ... dann ..., sonst ...
Wie wir schon erfahren haben, kann aufgrund dieser Logik auch nur eine der Blöcke der Verkettung ausgeführt werden.
Wir schauen also, ob x dem Wert "eier" entspricht. Wenn ja, geben wir True (wahr) zurück, ansonsten schauen wir, ob x dem Wert "schmalz" entspricht und geben, falls dies so ist True (wahr) zurück. Das machen wir dann mit jedem Wert so weiter. Wenn wir am Ende keinen Treffer erhalten haben, also keine der Bedingungen wahr war, kommt das else ins Spiel, welches False zurückgibt.
Kleiner Spoiler: Wir können die Funktion später auf nur einen Block mit nur einer Zeile reduzieren.
Wir haben uns jetzt schon ausgiebig mit den Strings als Listen beschäftigt. Die Vorgehensweise bei "normalen" Listen ist allerdings nicht groß anders. Auch die Funktionen, die wir anwenden können sind, bis auf einige Ausnahmen identisch (Eine Liste aus Zahlen können wir z.B. natürlich nicht in Kleinbuchstaben verwandeln, wie einen String).
Ein wenig anders sieht es bei der Definition aus. Strings haben wir mit " definiert, bei Nicht-String-Listen schaut das ein wengig aus. Diese können wir mit unseren Altbekannten eckigen Klammern definieren, indem wir innerhalb der Klammern unsere gewünschten Werte mit Komma getrennt eingeben. Ein Beispiel:
# Liste aus 3 Elementen wird definiert
x = [1, 2, 4]
print(x[0])
print(x[1])
print(x[2])
Wie versprochen können wir jetzt auch - im Gegensatz zu Strings - unsere Datentypen in einer Liste mischen:
# Liste mit verschiedenen Datentypen
x = [42, 3.14, "Hallo"]
print("Anzahl Elemente:", len(x))
print("Index 0:", x[0], type(x[0]))
print("Index 1:", x[1], type(x[1]))
print("Index 2:", x[2], type(x[2]))
Im Beispiel oben haben wir einen String als Element, der ja auch eine Liste ist. Das ist kein Problem, eine Liste kann selbst ein Element einer Liste sein, da können wir beliebig tief verschachteln.
Das wars im Grunde auch schon mit den allgemeinen Listen
Mit der while-Schleife haben wir schon die Möglichkeit kennengelernt, bestimmte Befehle so lange zu wiederholen, bis die Bedingung, die wir dafür definiert haben, nicht mehr wahr ist.
Wir möchten allerdings nicht immer etwas auf Basis einer Bedingung wiederholen. Oft haben wir auch eine bestimmte Anzahl an Elementen, die wir zum Beispiel aus einer Liste entnehmen und einen bestimmten Code für jedes Element einer Liste ausführen möchten. Dafür haben wir die for-Schleife.
Das erklärt sich am besten an einem Beispiel:
# Liste mit verschiedenen Datentypen
x = [42, 3.14, "Hallo"]
for i in x:
print(i)
In diesem Beispiel geben wir alle Elemente der Liste x nacheinander aus.
Mit dem Wort for leiten wir die for Schleife ein. Dann benennen wir die Variable i als "Durchlaufvariable". Die Variable i wird also bei jedem Durchgang mit dem aktuellen Wert befüllt. Dann schreiben wir das Schlüsselwort in, gefolt von unserer Liste, aus der wir auswählen wollen, in diesem Fall x. Und zu guter Letzt noch der Doppelpunkt, um unseren Block einzuleiten.
Das ganze liest sich also so: Für jedes Element i aus der Liste x mache
Im oberen Beispiel wird alles eingerückte im Block also 3 mal ausgeführt, i ist im ersten Durchgang 42, im zweiten 3.14 und im dritten "Hallo".
# Diese Zelle bitte einmalig ausführen!
from hsmwgk.test import test
def die_antwort():
return 42
# Die letzte Zeile nicht löschen
# Diese prüft, ob die Lösung stimmt!!!
test(die_antwort)
# WICHTIG: Die Ausgabe sollte hier "Die Lösung ist korrekt :)" sein.
Schreiben Sie die Funktion kuchen_backen
.
An diese Funktion wird je eine zufällige Zutat in Kleinbuchstaben als String übergeben. Die Funktion soll True
zurückgeben, wenn eine Zutat aus dem nachfolgenden Lied übergeben wurde:
Wer will guten Kuchen backen,\
der muss haben sieben Sachen:\
eier
und schmalz
,\
zucker
und salz
,\
milch
und mehl
,\
safran
macht den Kuchen gel!
Wir können unsere Lösung für Aufgabe 2 nun mit dem gelernten optimieren.
def kuchen_backen(x):
for i in ["eier", "schmalz", "zucker", "salz", "milch", "mehl", "safran"]:
if x == i:
return True
return False
test(kuchen_backen)
Diese Lösung ist doch gleich viel kürzer.
In der for-Schleife definieren wir eine Liste mit all unseren zu prüfenden Wörtern. In jedem Durchlauf prüfen wir dann, ob das jeweile Wort dem eingegebenen Parameter entspricht. Sollte dies der Fall sein, wird True zurückgegeben. Sobald wir einen return erreicht haben, wird die Funktion auch an genau dieser Stelle beendet. Das ist ganz wichtig, da das return False außerhalb der for-Schleife keine Bedinung hat. Wenn die Funktion nicht vorher durch ein return abgebroch wird, wird auf jeden False zurückgegen (In diesem Fall, wenn in der For-Schleife kein Treffer gefunden wurde).
Es geht aber sogar noch kürzer:
def kuchen_backen(x):
return x in ["eier", "schmalz", "zucker", "salz", "milch", "mehl", "safran"]
test(kuchen_backen)
In diesem Kontext ist das "... in ..." als Aussage zu verstehen. Wir formulieren damit praktisch die Aussage, dass x in der nachfolgenden Liste zu finden ist. Sollte dies so sein, wird ein True zurückgegeben, ansonsten ein False.
Schreiben Sie die Funktion snake_case
. Diese wandelt einen Funktionsnamen (String) im Camel Case in den Snake Case um. Übergeben wird dabei ein Funktionsname (String) in Camal Case.
Camel Case ist die folgende Schreibweise von Funktionsnamen:
Beispiel: halloWelt
, kuchenBacken
, kleinerGruenerKaktus
Ihre Funktion soll die Zeichenkette ins snake case überführen und zurückgeben. Snake Case ist die folgende Schreibweise:
Beispiel: hallo_welt
, kuchen_backen
, kleiner_gruener_kaktus
Diese Übung ist ein wenig kompliziert, aber überlegen wir uns mal, wie wir das Problem lösen. Der Unterschied zwischen der Eingabe (Camel Case) und der Ausgabe (Snake Case) ist die Worttrennung. Da wir keine Leerzeichen in Variablennamen verwenden dürfen, müssen wir uns anders behelfen. Bei Camel case fangen wir klein an und ein neues Wort wird dann immer mit einem Großbuchstaben angefangen. Bei Snake Case schreiben wir alles klein und der Unterstich (_) dient uns als Ersatz für das Leerzeichen.
Wir müssen also im Grunde die Großbuchstaben von Camel Case in Kleinbuchstaben verwandeln und einen Unterstrich davorsetzen. Das ist schon die ganze theoretische Lösung. In der Praxis können wäre aber ein Ersetzen, dadurch, dass noch ein weiteres Zeichen eingefügt, anstatt nur ersetzt werden muss, zu umständlich. Deshalb gehen wir die Eingabe Zeichen für Zeichen durch und bauen uns die Ausgabe Stück für Stück zusammen. Das sieht dann so aus:
def snake_case(eingabe):
ausgabe = ""
for zeichen in eingabe:
if zeichen.isupper():
ausgabe = ausgabe + "_" + zeichen.lower()
else:
ausgabe = ausgabe + zeichen
return ausgabe
test(snake_case)
Dabei passiert folgendes:
Am Anfang definieren wir unsere Ausgabe als leer (""), da wir sie ja Stück für Stück zusammenbauen. Danach gehen wir mit einer for Schleife jedes Zeichen der Reihe nach durch.
Innerhalb dieser Schleife prüfen wir mit der Funktion isupper(), die wir mit dem Punkt auf zeichen anwenden, ob das jeweilige Zeichen ein Großbuchstabe ist (Dann gibt die Funktion True zurück, ansonsten False).
Sollte dies nicht der Fall sein, wird im else einfach ausgabe neu definiert aus ausgabe mit dem angehängten aktuellen Zeichen. Wenn die Bedingung aber wahr ist, also das Zeichen ein Großbuchstabe ist, definieren wir ausgabe neu als ausgabe mit angehängten Unterstrich und hängen dann noch unser mit lower() in klein umgewandeltes aktuelles Zeichen an.
Wenn wir mit allem durch sind, geben wir unsere fertige Ausgabe mit return zurück.
Schreiben Sie die Funktion quersumme
.
Die Quersumme ist die Summe der einzelnen Zahlen einer Zahl, also z.B. "135" hat die Quersumme 1+3+5 = 9.
Übergeben wird eine Ganzzahl. Geben Sie die Quersumme zurück.
Diese Aufgabe lösen wir, genau wie die letzte Stück für Stück.
Dafür definieren wir unsere Quersumme in der Variable summe mit 0 und addieren dann jede einzelne Ziffer in jedem Durchgang unserer for-Schleife dazu.
Wir müssen dabei aber auf jeden Fall etwas beachten. Zahlen sind, wie weiter oben beschrieben, für den Computer nur eine Reihe Einsen und Nullen. Eine Zahl, die wir als Dezimalzahl können wir daher nicht einfach in ihre einzelne Ziffern zerlegen. Wir können aber die Zahl sehr wohl in einen String (Zeichenkette) umwandeln. Dann ist die Zahl praktisch keine Zahl mehr, sondern nur noch einzelne Zeichen und wir können diese mit der for-Schleife nun einzeln bearbeiten.
Wir müssen dann nur beim Addieren darauf achten, die einzelne Ziffer als Zeichen wieder in eine richtige Zahl umzuwandeln. Dann noch summe mit return zurückgeben. Und fertig.
def quersumme(eingabe):
summe = 0
for i in str(eingabe):
summe = summe + int(i)
return summe
test(quersumme)