Tag 3: Funktionen & Standardbibliothek#
Bisher haben wir einzelne Code-Stücke geschrieben und nacheinander ausgeführt. Mit ersten Funktionen sind Sie bereits mit den Funktionen print() und len() aus den vorherigen Tagen vertraut. Python bietet mehrere eingebaute Funktionen wie diese, aber Sie können auch Ihre eigenen Funktionen schreiben. Eine Funktion ist wie ein Miniprogramm innerhalb eines Programms. Im Folgenden führen wir erst in Funktionen ein und wiederholen damit, die Inhalte der letzten Tage.
Definition: Mit dem Schlüsselwort def können Funktionen definiert werden, gefolgt von einem Namen und eventuell Parametern.
def hello_world():
print('Hi')
Parameter und Rückgabewerte: Funktionen können Parameter akzeptieren und Werte zurückgeben, die mit dem return-Statement definiert werden.
def addition(x, y):
return x + y
Eingebaute Module: Python bietet eine Vielzahl von eingebauten Modulen in der Standardbibliothek, die eine breite Palette von Funktionen und Werkzeugen für verschiedene Aufgaben bereitstellen.
Um besser zu verstehen wie Funktionen funktionieren und wie wir selber welche schreiben können, erstellen wir nun eine einfache erste Version.
def hello(): # mit 'def' wird eine Funktion definiert, hello_world ist der Name der Funktion
print('Hi')
print('Guten Tag')
hello() # mit dem Namen und Klammern wird eine Funktion aufgerufen
# Ausgabe
# Hi
# Guten Tag
Hierbei wird die Funktion mit dem Schlüsselwort def eingeleitet. Der Funktion wird der Name hello_world gegeben und es werden keine Parameter übergeben (). Durch die folgende Einrückung der vier print() Aufrufe, ist klar, was zu Funktion gehört und was nicht. Der Funktionsaufruf hello() ist nicht mehr eingerückt und gehört somit nicht mehr zur Funktion. Dieser ruft dann die Funktion auf. Wichtig ist, dass Funktionen erst definiert werden müssen, bevor sie aufgerufen werden können. D.h. die Funktion muss im Code ‘über’ dem Aufruf stehen.
Die Möglichkeit Funktionen Parameter ‘übergeben’ zu können ermöglicht es beispielsweise auf Grundlage dessen Entscheidungen in der Funktion treffen zu können. So kann bspw. entschieden werden, ob höflich oder leger gegrüßt werden soll.
def hello(art_der_begruessung):
if art_der_begruessung == True:
print('Hi')
else:
print('Guten Tag')
art_der_begruessung = True
hello(art_der_begruessung) # Funktionsaufruf mit Parameter
# Ausgabe
# Guten Tag
Die Funktion von oben aktzeptiert nun einen Parameter art_der_begruessung
. Dieser wird als Boolean in dem If-Else-Ausdruck verwendet um zu unterscheiden ob nur leger gegrüßt wird (True) oder höflicher (False). Wichtig ist, dass im Aufruf hello(art_der_begruessung)
der Parameter entsprechend übergeben wird. Dieser muss nicht den selben Namen aufweisen - hello(True)
würde genauso funktionieren.
Formalisiert wäre eine Funktion:
def funktionsname(optionale_parameter):
""" docstring - Beschreibung"""
# statement(s)
return value # optional
funktionsname(parameter) # Funktionsaufruf
Der erste Teil def funktionsname(optionale_parameter):
wird auch header genannt. Der eingerückte Teil wird body genannt. Funktionen ermöglichen somit das mehrfache Nutzen von Funktionalitäten und ermöglicht das Teilen dieser Funktionalitäten an andere. Zudem kann Code so besser organisiert und wiederverwendet werden.
Kommen wir nun zu dem Eingangsbeispiel der Addtion wieder.
def addition(x, y):
add = x + y
return add
Diese Funktion ermöglicht uns, eine einfache Addition wiederzuverwenden. Diese Funktion haben wir natürlich schon als Operator +, jedoch könnten in dieser Funktion beispielweise noch unterschiedliche Überprüfungen hinzugefügt werden (bspw. dass es sich um einen Integer handeln muss) und mit Fehlern automatisch umgegangen werden (kommende Tage). Unterschiedlich zur vorangehenden Funktion ist, dass diese Funktion mit dem Schlüsselwort return etwas ‘zurückgibt’. In diesem Fall die Summe von x und y. Da die Funktion etwas zurück gibt, kann mit dem Aufruf einer Variable ein neuer Wert zugewiesen werden.
Beispiel:
a = 5
b = 10
summe = addition(a, b)
Hier werden zwei Variablen a und b mit den Werten 5 und 10 initialisiert und als Parameter der Funktion addition
übergeben. Diese werden in der Funktion der Reihenfolge nach den lokalen Variablen x (a) und y (b) zugewiesen. In der Funktion werden diese dann addiert und ‘zurückgegeben’. Damit wird mit der errechneten Summe der Addition in der Funktion nun die Variable summe
initialisiert. Summe
hat somit den addierten Wert der beiden Variablen a
und b
.
Exkurs: Globale und lokale Variablen
Globale und lokale Variablen unterscheiden, wo welche Variable wie zugeordnet ist.
Im obigen Beispiel ist art_der_begruessung
, die außerhalb der Funktion hello() definiert ist eine globale Variable. Innerhalb der Funktion ist art_der_begruessung
eine lokale Variable des gleichen Namens innerhalb.
Globale Variable: Diese Variable wird außerhalb von Funktionen definiert und kann von jeder Funktion im Programmcode verwendet werden. In diesem Beispiel wird art_der_begruessung
als globale Variable vor dem Funktionsaufruf mit dem Wert True
definiert.
Lokale Variable: Diese Variable wird innerhalb einer Funktion definiert und ist nur innerhalb dieser Funktion sichtbar. In diesem Beispiel ist art_der_begruessung
auch der Parameter der Funktion hello(). Diese lokale Variable hat Vorrang vor der globalen Variable mit dem gleichen Namen. Die Zuweisung von True oder False zu art_der_begruessung innerhalb der Funktion hello() beeinflusst nur die lokale Variable innerhalb des Funktionskontexts.
Sie müssen das nicht direkt komplett verstanden haben - wir kommen darauf zurück. Halten Sie es allerdings im Kopf.
Erforderliche und Optionale Parameter:
Funktionen können optionale Parameter haben, die beim Funktionsaufruf nicht mit übergeben werden müssen. Ein Beispiel haben Sie bereits kennengelernt, nämlich reverse=True
in der list.sort()
-Funktion.
Dazu definieren wir einen Standard-Wert für den Parameter im Funktions-Header:
def hallo(sprache, nett=True):
if sprache == 'DE':
if nett:
return "Moin"
else:
return "MoinMoin"
else:
if nett:
return "Hello"
else:
return "HelloHello"
In diesem Beispiel hat die Funktion hallo()
einen erforderlichen Parameter (den ersten, nämlich sprache
und einen optionalen Parameter (den zweiten, nämlich nett
). Für den Aufruf haben wir also zwei Möglichkeiten:
hallo('EN') # Gibt "Hello" zurück, "nett" hat den Standard-Wert von "True"
hallo('DE', False) #Gibt "MoinMoin" zurück
Im ersten Fall wird sprache
beim Funktionsaufruf den Wert EN
annehmen, nett
den Standard-Wert von True
. Im zweiten Fall werden beide Parameter übergeben, nett
hat also den Wert False
.
Wird die Funktion allerdings ohne Argument aufgerufen, erhalten wir einen Fehler:
>>> hallo()
Traceback (most recent call last):
File "<input>", line 1, in <module>
hallo()
TypeError: hallo() missing 1 required positional argument: 'sprache'
Python-Standardbibliothek#
Die Python-Standardbibliothek, auch bekannt als STDLIB, ist eine Sammlung von Modulen und Paketen, die mit Python geliefert werden und eine Vielzahl von nützlichen Funktionen und Werkzeugen für verschiedene Aufgaben bieten. Diese Bibliothek ist Teil der Python-Installation und muss nicht separat installiert werden.
Hier sind einige der Hauptbereiche, die von der Python-Standardbibliothek abgedeckt werden und was man damit machen kann:
Betriebssystemoperationen (
os
): Dasos
-Modul bietet Funktionen zum Arbeiten mit dem Betriebssystem, einschließlich Dateioperationen, Verzeichnisoperationen, Umgebungsvariablen und Prozesssteuerung (morgen)Mathematische Funktionen (
math
): Dasmath
-Modul enthält eine Vielzahl von mathematischen Funktionen und Konstanten, die für mathematische Berechnungen nützlich sind. Dazu gehören Funktionen für Trigonometrie, Logarithmen, Exponentialfunktionen, Runden und mehr.Zufallszahlen (
random
): Dasrandom
-Modul ermöglicht die Erzeugung von Pseudozufallszahlen. Es bietet Funktionen zum Generieren von Zufallszahlen, zur Auswahl von Zufallselementen aus Listen und zur Mischen von Sequenzen.Datum und Zeit (
datetime
): Dasdatetime
-Modul bietet Klassen und Funktionen zum Arbeiten mit Datum und Zeit. Es ermöglicht das Erstellen, Manipulieren und Formatieren von Datum und Zeit sowie die Berechnung von Zeitdifferenzen.Dateiverarbeitung (
io
): Dasio
-Modul bietet Tools zum Lesen und Schreiben von Dateien und Datenströmen. Es ermöglicht das Arbeiten mit Dateien im Speicher sowie das Umleiten von Ein- und Ausgaben.Reguläre Ausdrücke (
re
): Dasre
-Modul stellt Funktionen und Klassen zum Arbeiten mit regulären Ausdrücken bereit. Reguläre Ausdrücke werden verwendet, um Textmuster in Zeichenketten zu suchen und zu manipulieren.Datenkompression (
gzip
,zipfile
,zlib
): Python bietet verschiedene Module zur Datenkompression, einschließlichgzip
für GZIP-Komprimierung,zipfile
für ZIP-Archive undzlib
für die Verwendung des Zlib-Komprimierungsformats.Netzwerk- und Internetprotokolle (
socket
,urllib
): Diesocket
- undurllib
-Module ermöglichen die Kommunikation über Netzwerke und das Arbeiten mit Internetprotokollen wie HTTP, FTP und SMTP.
Einige dieser Module müssen vor der Nutzung importiert werden. Das schauen wir uns am letzten Tag an. Importieren von Modulen:
Dies sind nur einige Beispiele für die Funktionen und Werkzeuge, die in der Python-Standardbibliothek enthalten sind. Schauen Sie in die Dokumentation für mehr Informationen. Meistens ist es schneller, einfacher und besser solche Funktionen zu nutzen, als für den selben Zweck eigene Funktionen zu schreiben.
Exkurs: Funktionen und Methoden
Sie werden ggf. im Verlauf dieser Woche noch den Begriff Methoden hören. Eine Methode ist auch eine Funktion, die an ein spezifisches Objekt oder eine spezifische Klasse gebunden sind. Klassen und Objekte sind Teile der Objekt-orientierten Programmierung. Dieses Thema werden wir morgen kurz streifen. Dennoch zur Vollständigkeithalber:
Methoden werden innerhalb der Definition einer Klasse definiert und können auf Objekte dieser Klasse angewendet werden. Sie haben immer einen impliziten ersten Parameter, der normalerweise self genannt wird und auf das Objekt selbst verweist. Der Aufruf einer Methode erfolgt über das Objekt, dem sie zugeordnet ist, gefolgt von einem Punkt und dem Namen der Methode.
Tüftelspaß und Knobeleien#
Das war’s auch schon mit neuem Inhalt für heute. Jetzt ist Zeit zum Fragen stellen! Stellen Sie gern Fragen zu jeglichen Inhalten der letzten Tage - direkt im Plenum oder wie gehabt im allg. Markdown-Dokument.
Tipp
Besprechen Sie sich erst in der Gruppe wie was wo wann gemacht werden sollte. Sie dürfen eng zusammenarbeiten, gern auch im Pair-programming, jedoch sollte letztlich jede*r alles verstanden haben.
Erste Tüfteleien
Schreiben Sie eine Funktion devision, die zwei Variablen aufnimmt , verarbeitet und das Ergebnis ausgibt. Berechnen Sie das mittels dieser Funktion das Ergebnis von: 8958937768937 geteilt durch 2851718461558. Was kommt raus?
Schreiben Sie eine Funktion multiplikation und errechnen Sie mit dieser Funktion, wieviele Sekunden ein Jahr mit 365 Tagen hat.
Tipp
Berechnen Sie erst die Sekunden pro Minute, dann pro Stunde und dann pro Tag
Nutzen Sie die Methoden der Standardbibliothek für Strings und finden Sie heraus, wieviele Buchstaben das Wort
'Donaudampfschifffahrtselektrizitätenhauptbetriebswerkbauunternehmenbeamtengesellschaft'
hat. Welcher Vokal ist am häufigsten vertreten? Wie oft?Schreiben Sie für jede dieser Zählungen oder Vergleiche eine eigene Funktion. Tipp: Es können auch Funktionen innerhalb von Funktionen aufgerufen werden.
Tipp
Die Funktionen zum Länge des Strings und einzelne Buchstaben zählen sind schon in der Standardbibliothek definiert und können von Ihnen wiederverwendet werden.
[Built in String Methods](https://docs.python.org/3/ library/stdtypes.html#string-methods)
[Built in String Methods - etwas übersichtlicher - dafür jedoch nicht vollständig](https://www.w3schools. com/python/ python_ref_string.asp)
Auflösung: Versuchen Sie es erst selbst!
s = 'hallo'; len(s); s.count('vokal')
Wie viele Buchstaben hat die ausgeschriebene Version der chemischen Formula Titin im Englischen? Welcher Buchstabe ist hier der häufigste? Nutzen Sie gern Ihre in Aufgabe 3 geschriebenen Funktionen.
Vorbereitung der Bastelei
Machen Sie sich mit der Extra Aufgabe am Ende von Tag 2 vertraut. Diese können Sie im Anschluss gern noch bearbeiten, gehen Sie dann jedoch bitte als Gruppe gemeinsam zu diesen Aufgaben über. Das Ziel letztliche dieser Aufgabe ist es, für alle Städte die Einwohnerdichte herauszufinden. Zunächst müssen jedoch die Daten “gereinigt” werden. Also für die entsprechende Aufgabe so vorbereitet werden, dass eine Verarbeitung möglich ist.
Tipp:
Versuchen Sie immer erst nur mit einem Wert eine Lösung zu finden und weiten Sie dann diese Lösung auf die gesamte Liste an.
Sie finden in der Datengrundlage zwei Listen mit Informationen zu Flächen und Einwohnerzahlen. Diese sind ergänzende Informationen zu den Städten und Ländern der Extra Aufgabe von gestern.
Datengrundlage
Achtung! Reihenfolge sollte nicht (ohne Überlegung) verändert werden, da die Listen sonst nicht mehr zueinander passen!
flaeche = ['0219 km²', '0012 km²', '0362 km²', '0360 km²', '0892 km²', '0062 km²', '0368 km²', '0161 km²', '0525 km²', '0228 km²', '0120 km²', '0007 km²', '0119 km²', '0715 km²', '0839 km²', '0077 km²', '0085 km²', '0275 km²', '1.572 km²', '0052 km²', '0606 km²', '0305 km²', '0002 km²', '1.081 km²', '0111 km²', '0459 km²', '0105 km²', '0108 km²', '0496 km²', '0275 km²', '0307 km²', '1.285 km²', '0142 km²', '0571 km²', '492 km²', '0187 km²', '0159 km²', '0042 km²', '0017 km²', '0001 km²', '0000,44 km² 6', '0402 km²', '0518 km²', '0415 km²', '0641 km²']
einwohnerzahl = ['872.757 (2019)', '23.498 (2020)', '664.046 (2011)', '1.344.844 (2016)', '3.664.088 (2020)', '134.794 (2020)', '440.948 (2020)', '1.067.557 (2009)', '1.697.343 (2005)', '1.821.000 (2018)', '593.800 (2006)', '4.376 (2008)', '506.211 (2006)', '559.330 (2004)', '2.687.610 (2005)', '569.557 (2014)', '517.802 (2005)', '278.638 (2007)', '7.421.209 (2007)', '115.227 (2016)', '3.155.399 (2005)', '1.741.371 (2004)', '36.136 (2012)', '11.503.501 (2010)', '276.410 (2012)', '613.285 (2012)', '2.220.445 (2014)', '143.718 (2008)', '1.181.610 (2005)', '111.721 (2007)', '731.672 (2005)', '2.547.932 (2005)', '304.065 (2007)', '474.019 (2003)', '1.307.439 (2021)', '766.747 (2005)', '403.505 (2006)', '600.339 (2006)', '5.109 (2006)', '6.300 (2005)', '932 (2005)', '553.904 (2006)', '1.864.679 (2021)', '1.931.593 (2022)', '780.097 (2005)']
Fügen Sie zunächst die Daten in Ihren Code ein und schauen Sie sich die Datengrundlage genauer an. Was muss mit den Daten passieren, damit Sie mit ihnen eine Einwohnerdichte berechnen können?
Datenbeschaffung und -bereinigung sind häufig große Teile im wissenschaftlichen Arbeiten. Daten in der freien Wildbahn können komplex, schwer zu verstehen, unvollständig und fehlerhaft sein. Seltenst sind Daten direkt verarbeitbar. Die Bereinigung, also Überprüfung und Vorbereitung, der Daten für die gewollte Verarbeitung, ist somit ganz normaler Teil der wissenschaftlichen Praxis. Diesen Schritt werden Sie nun im Folgenden auch durchlaufen.
Für die Fläche werden wir dies nun gemeinsam durchgehen, für die Einwohnerzahl ist es dann Ihnn überlassen eine Lösung zu finden. Initialisieren Sie nun mit dem ersten Element der Flächen-Liste eine neue Variable und geben Sie sie aus.
Bei der Fläche wäre dies der Wert
f1 = '0219 km²'
an der Indexstelle ‘0’ der Liste. Um letztlich eine Berechnung von Fläche und Einwohnerzahl zu ermöglichen, müssen die Daten mit dem Datentyp ‘float’ vorliegen. Die Daten bisher liegen noch als ‘String’ vor und sind somit noch nicht numerisch zu verarbeiten. Den Prozess einen Datentyp in einen anderen Datentyp zu verwandeln nennt sich casten. In diesem Fall wäre dies:float('0219 km²)
. Probieren Sie dies gern im REPL aus und schauen was passiert.
Casting von Datentypen
“Casting” ist der Prozess, bei dem ein Datentyp in einen anderen Datentyp umgewandelt wird. Wenn Sie zum Beispiel eine Zahl als Text haben und sie als Zahl verwenden möchten, müssen Sie sie “casten”, indem Sie sie in einen numerischen Datentyp umwandeln.
Ein einfaches Beispiel ist das “Casten” eines Strings in eine Ganzzahl:
zahl_als_text = "123"
zahl_als_zahl = int(zahl_als_text)
Hier wird der String “123” in die Ganzzahl 123 umgewandelt. Dies ermöglicht es Ihnen, mathematische Operationen mit der Zahl durchzuführen, wie zum Beispiel zahl_als_zahl * 2
.
Versuchen Sie nun herauszufinden woran es liegt, dass der String nicht in einen Gleitkommadatentyp (float) überführt werden kann. Das können Sie versuchen, indem Sie einzelne Teile des Wertes versuchen zu casten - so können Sie das Problem genauer definieren.
Sie werden erkannt haben, dass einige Inhalte des Strings nicht konvertierbar sind. Anderes jedoch überraschenderweise funktioniert. Versuchen Sie dies nun auch mit einem anderen Wert der Datengrundlage ‘Fläche’, um sicher zu gehen, dass Ihre Methodik für alle Daten in der Datengrundlage das selbe Ergebnis liefert.
Um nicht händisch jeden String im Folgenden überarbeiten zu müssen, sollten Sie nun versuchen einen Weg zu finden, wie Sie das automatisch bewerkstelligen können. Sprechen Sie sich in Ihrer Gruppe ab und erörtern und testen Sie potentielle Möglichkeiten. Gern auch im Peer-Programming.
Tipp
Schauen Sie sich das slicing noch mal genauer an. Kann man dies auch bei bestimmten Characters machen? Denken Sie daran, ein Leerzeichen ist auch ein Character - die Standardbibliothek könnte da weiterhelfen
Tipp 2
strip() und float()
Wenn Sie nicht weiterkommen, treten Sie gedanklich ein Stück zurück oder malen Sie sich den Ablauf auf ein Stück Papier auf. Geben Sie sich dafür zusammen noch 10 Minuten zum Ausprobieren und Fragen Sie dann nach.
Wenn Sie eine Lösung gefunden haben versuchen Sie diese nun auf alle Elemente in der Liste anzuwenden. Tipp: Ggf. hilft Ihnen eine Kombination aus for-Schleife für den Zugriff auf jedes Element der Liste und eine Funktion, die den String entsprechend bearbeitet und wieder zurückgibt.
Tipp
Sie können zwei for-Schleifen Ansätze versuchen. Einmal einen indexbasierten Ansatz und einmal das direkte bearbeiten der Liste
flaeche_bereinigt = []
for i in range(0, len(flaeche)):
# extrahieren Sie das Element aus der Liste der Fläche an der entsprechenden Indexstelle
# rufen Sie ihre Funktion zum Bereinigen des Strings auf und übergeben Sie der Funktion das gerade extrahierte Element. Initialisieren Sie eine neue Variable mit dem bereinigten String, welchen Ihre Funktion zurückgibt (return)
# Fügen Sie der flaeche_bereinigt Liste den neuen bereinigten String zu
# oder:
flaeche_bereinigt = []
for element in liste:
# Hier ist jedes *element* schon extrahiert. Ein Indexaufruf ist somit nicht nötig.
# Übergeben Sie das Element dan Ihre Funktion zum bereinigen und initialisieren Sie eine neue Variable
# Fügen Sie der flaeche_bereinigt Liste den neuen bereinigten String zu
Überprüfen Sie Ihr Ergebnis, indem Sie sich die neue Liste ausgeben lassen. Hat alles funktioniert?
Nun sind Sie dran! Bereinigen Sie die Liste der Einwohnerzahlen.
Schreiben Sie nun eine Funktion, um die Einwohnerdichte zu berechnen und testen Sie dies mit einzelnen Werten.
Wenden Sie nun beide Listen auf die eben geschriebene Funktion an und errechnen Sie für alle Werte die Einwohnerdichte und speichern Sie diese in einer neuen Liste ‘einwohnerdichte’.
Aufgabe 3: Ausgewachsene Knobelei - für Daniel Düsentriebe
Nehmen Sie sich nun auch noch die Informationen von gestern bzgl. der Namen der Hauptstädte.
Welche Stadt hat die größte Bevölkerung?
Welche die niedrigste Dichte?
Und welche die durchschnittlichste Größe (arithmetisches Mittel der flaeche)?
Kann Ihnen hier ein Dictionary helfen?
Denken Sie daran, dass Sie Datentypen auch ‘verschachteln’ können. Sie können somit Listen in Listen oder Listen in Dictionaries geben.