Funktionen II
Jetzt, wo du weißt, wie man Funktionen in der Praxis einsetzt, gibt es einige weitere Konzepte, die dir helfen werden, das Verhalten von Funktionen nicht nur in Python zu verstehen, sondern auch in anderen Sprachen.
Geltungsbereich (Scope)
Globale und lokale Variablen
Stell dir vor, du möchtest eine leicht abgeänderte Funktion printBirthdayGreeting() von vorher verwenden
und du möchtest das Alter bei jedem Aufruf der Funktion erhöhen:
name = "Johann"
alter = 32
def printBirthdayGreeting():
alter += 1
return "Happy Birthday " + name + ", du bist " + str(alter) + " Jahre alt!"
printBirthdayGreeting()
Kannst du erkennen, was falsch ist? Wenn du versuchst, den Code auszuführen, wirst du wahrscheinlich diese Meldung erhalten: UnboundLocalError: local variable ‚alter‘ referenced before assignment``.
Um dies zu verstehen, müssen wir über den Geltungsbereich (Scope) sprechen. Scope ist eine ‚Umgebung‘, in der eine Variable definiert ist, und auf die dort zugegriffen und in die geschrieben werden kann. Unter diesem Gesichtspunkt kennen wir zwei Typen von Variablen: globale und lokale.
Standardmäßig sind alle Variablen, die innerhalb einer Funktion definiert sind, lokal - du kannst nicht auf sie außerhalb der Funktion zugreifen. Und da der Geltungsbereich innerhalb der Funktion anders ist als der globale, ist es möglich, den gleichen Namen für zwei verschiedene Variablen zu verwenden.
Kannst du jetzt erklären, was im obigen Codeschnipsel passiert ist?
alter außerhalb der printBirthdayGreeting() Funktion ist eine globale Variable. Wenn wir jedoch innerhalb der
Funktion darauf zugreifen wollen, betrachtet Python es als eine neue lokale Variable. Wie lösen wir das Problem? Wir
können die Variable alter als global deklarieren:
name = "Johann"
alter = 32
def printBirthdayGreeting():
global alter
alter += 1
return "Happy Birthday " + name + ", du bist " + str(alter) + " Jahre alt!"
Dadurch weiß Python, dass die age-Variable, die wir meinen, im globalen „Namespace“ (wortwörtlich Namensbereich) liegt.
Warnung
Globale Variablen zu verwenden ist generell eine schlechte Praxis und du solltest es vermeiden, da es den Zweck deiner Funktionen weniger offensichtlich macht und du am Ende mit
‚Spaghetti‘ Code kämpfen musst. Ein besserer Weg ist es, die Variable age als eines der Argumente der Funktion zu übergeben (Beispiel unten).
Hier ist ein Beispiel für eine Funktion, die Variablen als Argumente übergibt:
def printBirthdayGreeting(name, alter):
alter += 1
return "Happy Birthday " + name + ", du bist " + str(alter) + " Jahre alt!"
Tipp
Du wirst oft von „Best Practices“ hören. Wie bestimmst du, was eine Best Practice ist und was nicht? Im Allgemeinen ist eine Best Practice das, was deinen Code für andere besser lesbar macht. Du kannst dir Styleguides für eine Sprache ansehen, in der du programmierst, aber am Ende geht es immer um gutes Urteilsvermögen, da keine Regel in allen Fällen passt.
Quelle: xkcd https://xkcd.com/1513/
Nicht-lokale Variablen
Ein kurioser Fall tritt bei der Verwendung von verschachtelten Funktionen auf. Sagen wir, du willst eine lokale Variable der Funktion nurEinBeispiel() ändern, indem du die verschachtelte
Funktion:
def nurEinBeispiel():
def weiteresBeispiel():
variable = "Innere Funktion, die alles verändert!"
variable = "Äußere Funktion"
weiteresBeispiel()
print(variable)
nurEinBeispiel()
Du weißt bereits, warum das nicht funktioniert. Aber wie kannst du das Problem umgehen? Du kannst die Variable nicht global deklarieren, weil sie innerhalb einer Funktion ist - sie ist lokal und es gibt
einen weiteren lokalen Bereich innerhalb der Funktion weiteresBeispiel(). Um diese Situation zu lösen, kannst du eine Variable als nonlocal deklarieren:
def nurEinBeispiel():
def weiteresBeispiel():
nonlocal variable
variable = "Innere Funktion, die alles verändert!"
variable = "Äußere Funktion"
weiteresBeispiel()
print(variable)
nurEinBeispiel()
Jetzt sollte der Code "Innere Funktion, die alles verändert!" genau so ausgeben, wie wir es wollten.
Bemerkung
Um mehr über Namespace und Scope in Python zu erfahren, schau dir die Dokumentation an.
Parameter übergeben
Ein wichtiges Konzept, das einen sichtbaren Einfluss auf die Funktionsweise deiner Funktionen haben wird, ist die Übergabe von Parametern. Dies beschreibt die Art und Weise, wie eine Variable verarbeitet wird, wenn man sie an eine Funktion übergibt - in einem Pass-by-Value Szenario wird das Argument als neue lokale Variable behandelt und hat keinen Einfluss auf die ursprüngliche Variable (falls eine Variable als Argument übergeben wurde). Im Falle von Pass-by-Reference kann die als Argument übergebene Variable innerhalb einer Funktion beeinflusst werden. In Python ist die Methode der Parameterübergabe eine spezielle Kombination aus beidem - Parameter werden per Wert der Objektreferenz übergeben.
Für eine gute Erklärung der Parameterübergabe und den Unterschied zwischen den verschiedenen Techniken, empfehle ich dir diesen Blogpost von Robert Heaton zu lesen.