Python unter Linux: Funktionen
Funktionen gliedern den Programmtext, gestalten den Code übersichtlich und ersparen dem Programmierer wertvolle Entwicklungszeit. Ebenfalls sind sie eine sehr gute Schnittstelle, um im Team gemeinsam an Aufgaben zu arbeiten.
Funktionen
BearbeitenFunktionen werden wie folgt definiert und aufgerufen:
#!/usr/bin/python
def HalloWelt():
print "Hallo, Welt!"
HalloWelt()
HalloWelt()
user@localhost:~$ ./funk1.py
Hallo, Welt!
Hallo, Welt!
Dem Schlüsselwort def folgt der Funktionsname. Die Anweisungen der Funktion folgt als Block. Funktionen können Parameter haben und diese nutzen:
#!/usr/bin/python
def HalloWelt(anzahl):
if anzahl > 0:
for i in xrange(0, anzahl):
print "Hallo, Welt!"
HalloWelt(3)
user@localhost:~$ ./funk2.py
Hallo, Welt!
Hallo, Welt!
Hallo, Welt!
Eine der Aufgaben von Funktionen ist es, Werte zurückzuliefern, wobei jeder Typ zurückgegeben werden kann. Wir beschränken uns in den Beispielen auf Zahlen:
#!/usr/bin/python
def summe(a, b, c):
wert = a + b + c
return wert
print summe(1, 7, 3)
user@localhost:~$ ./funk3.py
11
Die folgende Funktion berechnet für jeden String die Buchstabensumme, wobei ein A für 1 steht, B für 2 und so fort. Kleinbuchstaben werden zunächst in Großbuchstaben umgewandelt. Danach wird die Summe ermittelt, wobei nur die Buchstaben A-Z gezählt werden:
#!/usr/bin/python
def StringWert(s):
s = s.upper()
summe = 0
for zeichen in s:
wert = ord(zeichen) - ord('A') + 1
if wert > 0 and wert <= 26:
summe += wert
return summe
print StringWert("ABBA")
print StringWert("Hallo, Welt!")
user@localhost:~$ ./funk4.py
6
108
Die Methode upper() kennen Sie schon, sie liefert einen String zurück, welcher nur aus Großbuchstaben besteht. Über diesen String wird iteriert. Mit ord() erhalten wir einen Zahlenwert für den aktuellen Buchstaben. Von diesem Zahlenwert ziehen wir den Zahlenwert des ersten Buchstabens (A) ab, und da wir nicht von 0, sondern von 1 beginnen wollen, müssen wir zur Werteberechnung noch 1 hinzu addieren.
Funktionen kann man auch ineinander schachteln, wie folgendes Beispiel zeigt:
#!/usr/bin/python
def Hypothenuse(Kathete1, Kathete2):
def Quadriere(x):
return x * x
def Summiere(a, b):
return a + b
Hyp = Summiere(Quadriere(Kathete1), Quadriere(Kathete2))
return Hyp
print "Das Hypothenusenquadrat lautet:", Hypothenuse(1, 2)
user@localhost:~$ ./funk5.py
Das Hypothenusenquadrat lautet: 5
Außerhalb der Funktion Hypothenuse() sind die Funktionen Quadriere() und Summiere() unbekannt.
Funktionsdokumentation
BearbeitenFunktionen können und sollten dokumentiert werden. Schreibt man mit passender Einrückung einen Doc-String, also einen anonymen mehrzeiligen String, in die Funktion, so kann man an anderer Stelle auf ihn Bezug nehmen. Es werden für jedes angelegte Objekt einige Zusatzinformationen generiert und abgespeichert.
#!/usr/bin/python
# -*- coding: utf-8 -*-
def Collatz(parm):
"""Bestimmt das nächste Collatz-Folgeelement vom Parameter parm.
Das nächste Folgeelement ist 3*parm + 1, wenn parm ungerade ist,
sonst parm/2 """
if parm % 2 != 0:
return 3 * parm + 1
else:
return parm / 2
print Collatz.__doc__
user@localhost:~$ ./fdoc1.py
Bestimmt das nächste Collatz-Folgeelement vom Parameter parm.
Das nächste Folgeelement ist 3*parm + 1, wenn parm ungerade ist,
sonst parm/2
Mit __doc__ wird auf eine automatisch erstellte und belegte Variable zugegriffen. Diese Variable wird erzeugt, wenn die Funktion angelegt wird. Falls keine Dokumentation angegeben wurde, enthält __doc__ einen leeren String.
Parameter
BearbeitenNachdem wir nun die Grundlagen der Funktionen behandet haben, wollen wir uns detailliert mit Parametern beschäftigen.
Parameter kann man mit Werten vorbelegen:
#!/usr/bin/python
def HalloWelt(anzahl=3):
print
if anzahl > 0:
for i in xrange(0, anzahl):
print "Hallo, Welt!"
HalloWelt(1)
HalloWelt()
user@localhost:~$ ./param1.py
Hallo, Welt!
Hallo, Welt!
Hallo, Welt!
Hallo, Welt!
Man gibt hierbei in der Parameterliste einen voreingestellten Wert an, den man beim Funktionsaufruf auch überschreiben kann. Hat man mehrere Parameter, kann man einzelne von ihnen vorbelegen und im konkreten Aufruf auch vertauschen:
#!/usr/bin/python
def summe(a=3, b=2):
return a + b
print summe()
print summe(a=4)
print summe(b=4)
print summe(b=2, a=1)
user@localhost:~$ ./param2.py
5
6
7
3
Variable Parameter
BearbeitenGerade bei Funktionen wie der Summenberechnung ist es praktisch, eine variable Anzahl an Parametern zu haben. Dadurch werden recht praktische Funktionen möglich, und das schreiben neuer Funktionen für jede Anzahl an Parametern entfällt:
#!/usr/bin/python
def summe(*list):
s = 0
for element in list:
s += element
return s
print summe()
print summe(1)
print summe(1, 2, 3, 4, 5, 6, 7, 8, 9)
user@localhost:~$ ./varparam1.py
0
1
45
Der Parameter *list ist hierbei ein Tupel, das abhängig von der Anzahl der im Aufruf erfolgten Argumente entweder leer (()) ist, oder die Argumente (1) und (1, 2, 3, 4, 5, 6, 7, 8, 9) enthält. Anschließend brauchen wir zur Summenberechnung nur noch über dieses Tupel zu iterieren.
Neben der Tupel-Form variabler Argumente gibt es noch die Dictionary-Form:
#!/usr/bin/python
def ZeigeListe(**liste):
print liste
ZeigeListe(a1=1, a2=2, a3=3)
ZeigeListe(Name="Schmitz", Vorname="Elke", Postleitzahl=44444)
user@localhost:~$ ./varparam2.py
{'a1': 1, 'a3': 3, 'a2': 2}
{'Name': 'Schmitz', 'Vorname': 'Elke', 'Postleitzahl': 44444}
Hier wird lediglich ein Dictionary aufgebaut, welches jeweils aus dem Argumentenwort und -wert besteht.
Globale und lokale Variablen
BearbeitenHaben funktionslokale Variablen den gleichen Namen wie Variablen, die außerhalb der Funktion definiert wurden, so werden globalere Variablenwerte weder lesend noch schreibend beim Zugriff berührt:
#!/usr/bin/python
wert = 42
print wert
def wertetest():
wert = 12
print wert
wertetest()
print wert
user@localhost:~$ ./global1.py
42
12
42
Neue Variablen werden so lokal es geht erzeugt. Hat eine neue Variable innerhalb einer Funktion den gleichen Namen wie eine andere Variable außerhalb, so wird nur die innere Variable genutzt.
Möchte man es anders haben, muss man explizit den Zugriff auf die globale Variable anfordern:
#!/usr/bin/python
wert = 42
print wert
def wertetest():
global wert
wert = 12
print wert
wertetest()
print wert
user@localhost:~$ ./global2.py
42
12
12
Das Schlüsselwort global sorgt hier für den Zugriff auf die außerhalb der Funktion definierte globale Variable. Bitte beachten Sie, dass Zugriffe auf globale Variablen die Lesbarkeit des Codes vermindern.
Funktionen auf Wertemengen
BearbeitenHat man eine Funktion geschrieben, die ein einzelnes Argument verarbeitet und möchte diese Funktion nun auf eine ganze Liste von Werten anwenden, so bietet sich die Funktion map an. Diese nimmt ein Funktionsargument wie auch eine Liste auf, wendet die Funktion auf jedes Element dieser Liste an und gibt eine Liste als Ergebnis zurück. Folgendes Beispiel verdeutlicht dies:
#!/usr/bin/python
def quadriere(x):
return x * x
quadratzahlen = map(quadriere, [1, 2, 3, 4, 5, 6])
print quadratzahlen
user@localhost:~$ ./map1.py
[1, 4, 9, 16, 25, 36]
Die Funktion quadriere() berechnet für jedes Element der Liste von 1 bis 6 die Quadratzahl und gibt eine Liste mit Quadratzahlen zurück. Selbstverständlich kann dieses konkrete Problem auch mit Hilfe einer for-Schleife gelöst werden, was man benutzt ist meist mehr eine Geschmacksfrage.
lambda
BearbeitenEine mit lambda erzeugte Funktion ist anonym, sie hat keinen Namen und wird nur in einem bestimmten Kontext genutzt, wie zum Beispiel mit map:
#!/usr/bin/python
quadratzahlen = map(lambda x: x * x, [1, 2, 3, 4, 5, 6])
print quadratzahlen
user@localhost:~$ ./lambda1.py
[1, 4, 9, 16, 25, 36]
Nach dem Schlüsselwort lambda folgt bis zum Doppelpunkt eine durch Kommata getrennte Aufzählung von Argumenten, hinter dem Doppelpunkt beginnt die Anweisung. lambda-Funktionen lassen sich auch nutzen, um während des Programmlaufes neue Funktionen zu erzeugen. Das folgende Beispiel demonstriert, wie eine Quadrat- und eine Wurzelfunktion neu erzeugt werden:
#!/usr/bin/python
def Exponential(z):
return lambda x: x**z
quadriere = Exponential(2)
wurzel = Exponential(0.5)
a = quadriere(2)
print a
b = wurzel(a)
print b
user@localhost:~$ ./lambda2.py
4
2.0
Die Funktion Exponential() erwartet ein Argument, mit dem die lambda-Funktion erzeugt wird. Die Funktion gibt nicht etwa den Wert dieser neuen Funktion zurück, sondern die neue Funktion selbst. So erzeugt quadriere = Exponential(2) eine neue Quadratfunktion, die man auch sogleich anwenden kann.
Listen erzeugen sich selbst
BearbeitenWo wir gerade dabei waren, mit map() Listen zu erzeugen, wird vielleicht auch folgende Syntax[1] etwas für Sie sein. Lehnen Sie sich zurück und genießen Sie die unglaubliche Vorstellung, wie eine Liste sich selbst erzeugt:
#!/usr/bin/python
liste = [x * x for x in xrange(1, 10)]
print liste
user@localhost:~$ ./comprehension1.py
[1, 4, 9, 16, 25, 36, 49, 64, 81]
Diese Liste wird aufgebaut, indem alle Werte, die xrange() liefert, quadriert werden. Wir haben es hier also wieder mit einer Liste von Quadratzahlen zu tun. Anders als bei der for-Schleife steht hier der Funktionskörper vor dem Schleifeniterator. Diese Code ist aber noch nicht alles, was wir Ihnen bieten können:
#!/usr/bin/python
liste = [x * x for x in xrange(1, 10) if x % 2 == 0]
print liste
user@localhost:~$ ./comprehension2.py
[4, 16, 36, 64]
Nun haben wir es mit einer Liste von Quadratzahlen zu tun, die aus der Menge der geraden Zahlen gebildet wurden. Das in der Liste nachgestellte if sorgt hier für eine Auswahl der Werte, die in die Vorschrift zur Listenbildung übernommen werden.
Um alle Dreier-Tupel einer Liste auszugeben, also alle Kombinationen einer dreielementigen Liste aufzuzählen, dient folgendes Programm:
#!/usr/bin/python
Liste = ['1', '2', '+']
Kreuz = [(a, b, c) for a in Liste for b in Liste for c in Liste]
print Kreuz
user@localhost:~$ ./comprehension3.py
[('1', '1', '1'), ('1', '1', '2'), ('1', '1', '+'), ('1', '2', '1'), ('1', '2', '2'), ('1', '2', '+'), ('1', '+', '1'), ('1', '+', '2'), ('1', '+', '+'), ('2', '1', '1'), ('2', '1', '2'), ('2', '1', '+'), ('2', '2', '1'), ('2', '2', '2'), ('2', '2', '+'), ('2', '+', '1'), ('2', '+', '2'), ('2', '+', '+'), ('+', '1', '1'), ('+', '1', '2'), ('+', '1', '+'), ('+', '2', '1'), ('+', '2', '2'), ('+', '2', '+'), ('+', '+', '1'), ('+', '+', '2'), ('+', '+', '+')]
Wie wir sehen, können wir Listen aus Tupel aus anderen Listen erzeugen.
Solche Listen können auch mit der Funktion filter erzeugt werden. Dieser übergibt man eine Funktion, die für Argumente bool'sche Werte zurückliefert und eine Liste, über die iteriert werden soll. Zurück erhält man eine Liste mit all jenen Werten, für die die Funktion True liefert:
#!/usr/bin/python
def durch3teilbar(x):
return x % 3 == 0
print filter(durch3teilbar, range(10))
user@localhost:~$ ./comprehension4.py
[0, 3, 6, 9]
Die Funktion durch3teilbar() ergibt True für alle Werte, die durch drei teilbar sind. Nur noch diese Werte verbleiben in der übergebenen Liste.
Generatoren
BearbeitenFunktionen wie range() und xrange() erzeugen Objekte, über die sich iterieren lässt, im einfachsten Fall Listen oder Tupel. Eine andere Art iterierbarer Objekte sind Generatoren, um die es hier geht.
Generatoren mit yield
BearbeitenEin Generator wird wie eine Funktion erzeugt und erstellt eine Folge von Werten. Einen Generator kennen Sie bereits, nämlich xrange(). Die Folge wird elementeweise bereitgestellt mit yield():
#!/usr/bin/python
def MeinGenerator():
yield(1)
yield(2)
yield(3)
for i in MeinGenerator():
print i
user@localhost:~$ ./yield1.py
1
2
3
yield() liefert beim ersten Aufruf des Generators den ersten Wert zurück und stoppt dann die Ausführung. Es wird hierbei also keine Liste erzeugt, sondern jeder Zugriff auf den Generator liefert den nächsten von yield() bereitgestellten Wert.
Werte in Generatoren lassen sich bequem in for-Schleifen erzeugen:
#!/usr/bin/python
def rueckwaerts(text):
length = len(text)
for i in xrange(length):
yield(text[length - i - 1])
for c in rueckwaerts("Hallo, Welt!"):
print "\b%c" % c,
print
user@localhost:~$ ./yield2.py
!tleW ,ollaH
Hier wird der Text rückwärts ausgegeben, wobei yield() angefangen vom letzten Zeichen jedes Zeichen des Textes zurückliefert. Da das Komma bei der print-Anweisung ein Leerzeichen einfügt, müssen wir mit einem Backspace (\b) dafür sorgen, dass dieses wieder entfernt wird.
Tipp: Die oben benutzte Funktion dient als einfaches Beispiel zur Demonstration von Generatoren. Wenn Sie sich aber fragen, wie eine Zeichenkette einfach rückwärts dargestellt werden kann, dann hängen Sie [::-1] an eine String-Variable oder an ein String-Literal. Das gleiche Ergebnis wie oben wäre über "Hallo, Welt!"[::-1] ebenfalls möglich. |
Generatorexpressions
BearbeitenAuch für Generatoren gibt es wieder eine abkürzende Schreibweise:
#!/usr/bin/python
genex = (i * i for i in xrange(5))
for wert in genex:
print wert
user@localhost:~$ ./genex1.py
0
1
4
9
16
Die Syntax ist ähnlich wie bei List Comprehensions, jedoch werden runde Klammern verwendet.
Zusammenfassung
BearbeitenWir haben gezeigt, wie man Funktionen definiert, Werte zurückgibt und Funktionen mit variablen Parameterlisten schreibt. Der Gebrauch von lokalen und globalen Variablen wurde erläutert wie auch die Anwendung der Funktionen auf Listen mit Hilfe von map(). Als Syntaxzucker gaben wir einen Einblick in anonyme Funktionen. List Comprehensions und Generatoren rundeten das Thema ab.
Anmerkungen
Bearbeiten- ↑ Diese Syntax nennt man " List Comprehension "