Wie immer gilt in Python auch hier: Python ermöglicht die Verwendung des funktionalen Paradigmas, erzwingt es aber nicht durch Einschränkungen, wie es reine funktionale Programmiersprachen tun. Typischerweise verwendet man in Python prozedurale, objekt-orientierte und funktionale Verfahren, z.B. kann man objekt-orientiertes und funktionales Programmieren verwenden, indem man Funktionen definiert, die als Ein- und Ausgabe Objekte verwenden.
In Python wird das funktionale Programmieren u.a. durch folgende Komponenten realisiert:
Die Methode iter() versucht für ein beliebiges Objekt einen Iterator zurückzugeben. Der Iterator gibt bei jedem Aufruf ein Objekt der Liste zurück und setzt den Pointer der Liste um eines höher. Objekte sind iterierbar (iterable) wenn sie die Methode iter() unterstützen, z.B. Listen, Dictionaries, Dateihandles usw.
In [1]:
#beispiel
a = [1, 2, 3,]
my_iterator = iter(a)
my_iterator.__next__()
Out[1]:
In [2]:
my_iterator.__next__()
Out[2]:
Python erwartet in bestimmten Kontexten ein iterierbares Objekt, z.B. in der for-Schleife:
In [3]:
for i in a:
print(str(i))
Das ist äquivalent zu
In [4]:
for i in iter(a):
print(str(i))
Man kann sich die vollständige Ausgabe eines Iterators ausgeben lassen, wenn man ihn als Parameter der list()- oder tuple() Funktion übergibt.
In [5]:
#beispiel
a = [1, 2, 3,]
my_iterator = iter(a)
list(my_iterator)
Out[5]:
In [6]:
my_iterator = iter(a)
tuple(my_iterator)
Out[6]:
Frage: Warum habe ich im letzten Beispiel den Iterator neu erzeugt? Kann man das weglassen?
List Comprehension sind ein Element (von vielen) des funktionalen Programmierens in Python. Der wichtigste Vorteil ist das Vermeiden von Nebeneffekten. Was heißt das? Anstelle des Verändern des Zustands einer Datenstruktur (z.B. eines Objekts), sind funktionale Ausdrücke wie mathematische Funktionen aufgebaut, die nur aus einem klaren Input und einen ebenso eindeutig definierten Output bestehen.
Prinzipielle Schreibweise:
[<expression> for <variable> in <iterable> <<if <condition> >>]
Im folgenden Beispiel ist es das Ziel, die Zahlen von 0 bis 9 ins Quadrat zu setzen. Zuerst die traditionelle Lösung mit einer for-Schleife, in deren Körper eine neue Datenstruktur aufgebaut wird.
In [7]:
#eine traditionelle for-Schleife:
squared = []
for x in range(10):
squared.append(x**2)
squared
Out[7]:
Und hier die Version mit List Comprehension:
In [1]:
[x**2 for x in range(10)]
Out[1]:
In [3]:
#a + bx
#2 + 0.5x
#x = 5 bis x = 10
[x*0.5 + 2 for x in range(5, 11)]
Out[3]:
Natürlich kann man den Rückgabewert von List Comprehensions auch in einer Variablen abspeichern.
In [9]:
squared = [x**2 for x in range(10)]
squared
Out[9]:
Man kann in list comprehensions auch mehrere geschachtelte for-Schleifen aufrufen:
In [11]:
#Aufgabe: vergleiche zwei Zahlenlisten und gebe alle Zahlenkombinationen aus, die ungleich sind
#Erst einmal die traditionelle Lösung mit geschachtelten Schleifen:
combs = []
for x in [1,2,3 ]:
for y in [3,1,4]:
if x != y:
combs.append((x, y))
combs
Out[11]:
Und nun als List Comprehension:
In [12]:
[(x,y) for x in [1,2,3] for y in [3,1,4] if x != y]
Out[12]:
Ersetzen Sie eine Reihe von Worten durch eine Reihe von Zahlen, die die Anzahl der Vokale anzeigen. Z.B.: "Dies ist ein Satz" -> "2 1 2 1".
map(FunktionX, Liste)
Die Funktion FunktionX wird auf jedes Element der Liste angewandt. Ausgabe ist ein Iterator über eine neue Liste mit den Ergebnissen
In [13]:
a = ["ein Haus", "eine Tasse", "ein Kind"]
list(map(len, a))
Out[13]:
prozedurale Schreibweise:
In [14]:
for i in a:
print(len(i))
Verwenden Sie map() um in einer Liste von Worten jedes Wort in Großbuchstaben auszugeben. Diskutieren Sie evtl. Probleme mit einem Nachbarn.
Lösen Sie Aufgabe 1 mit map()
filter(FunktionX, Liste)
Die Funktion FunktionX wird auf jedes Element der Liste angewandt. Konstruiert einen neuen Iterator, in den die Elemente der Liste aufgenommen werden, für die die FunktionX den Ausgabewert True hat.
Bsp.:
In [15]:
#returns True if x is an even number
def is_even(x):
return (x % 2) == 0
b = [2,3,4,5,6]
list(filter(is_even, b))
Out[15]:
Verwenden Sie filter, um aus dem folgenden Text eine Wortliste zu erstellen, in der alle Pronomina, Artikel und die Worte "dass", "ist", "nicht", "auch", "und" nicht enthalten sind:
"Ich denke auch, dass ist nicht schlimm. Er hat es nicht gemerkt und das ist gut. Und überhaupt: es ist auch seine Schuld. Ehrlich, das ist wahr."
Die Funktionen des itertools-Moduls lassen sich einteilen in Funktionen, die:
Diese Funktionen erzeugen einen neuen Iterator auf der Basis eines existierenden:
itertools.count(),itertools.cycle(), itertools.repeat(), itertools.chain(), itertools.isslice(), itertools.tee()
itertools.cycle(iterator) Gibt die Liste der Elemente in iterator in einer unendlichen Schleife zurück
In [16]:
import itertools
#don't try this at home:
#list(itertools.cycle([1,2,3,4,5]))
itertools.repeat(iterator, [n]) wiederholt die Elemente in iterator n mal.
In [17]:
import itertools
list(itertools.repeat([1,2,3,4], 3))
Out[17]:
itertools.chain(iterator_1, iterator_2, ...) Erzeugt einen neuen Iterator, in dem die Elemente von iterator_1, _2 usw. aneinander gehängt sind.
In [18]:
a = [1, 2, 3]
b = [4, 5, 6]
c = [7, 8, 9]
list(itertools.chain(a, b, c))
Out[18]:
Verknüpfen Sie den Inhalt dreier Dateien zu einem Iterator
itertools.filterfalse(Prädikat, iterator) ist das Gegenstück zu filter(). Ausgabe enthält alle Elemente, für die das Prädikat falsch ist.
itertools.takewhile(Prädikat, iterator) - gibt solange Elemente aus, wie das Prädikat wahr ist
itertools.dropwhile(Prädikat, iter)entfernt alle Elemente, solange das Prädikat wahr ist. Gibt dann den Rest aus.
itertools.compress(Daten, Selektoren) Nimmt zweei Iteratoren un dgibt nur die Elemente des ersten (Daten) zurück, für die das entsprechende Element im zweiten (Selektoren) wahr ist. Stoppt, wenn einer der Iteratoren erschöpft ist.
itertools.combinations(Iterator, r) gibt alle r-Tuple Kombinationen der Elemente des Iterators wieder. Beispiel:
In [19]:
tuple(itertools.combinations([1, 2, 3, 4], 2))
Out[19]:
itertools.permutations(iterator, r) gibt alle Permutationen aller Elemente unabhängig von der Reihenfolge in Iterator wieder:
In [20]:
tuple(itertools.permutations([1, 2, 3, 4], 2))
Out[20]:
Wieviele Zweier-Permutationen sind mit den graden Zahlen zwischen 1 und 101 möglich?
Mathematische Operationen: add(), sub(), mul(), floordiv(), abs(), ...
Logische Operationen: not(), truth()
Bit Operationen: and(), or(), invert()
Vergleiche: eq(), ne(), lt(), le(), gt(), and ge()
Objektidentität: is(), is_not()
In [21]:
a = [2, -3, 8, 12, -22, -1]
list(map(abs, a))
Out[21]:
lambda erlaubt es, kleine Funktionen anonym zu definieren. Nehmen wir an, wir wollen in einer List von Zahlen alle Zahlen durch 100 teilen und mit 13 multiplizieren. Dann könnten wir das so machen:
In [22]:
def calc(n):
return (n * 13) / 100
a = [1, 2, 5, 7]
list(map(calc, a))
Out[22]:
Diese Funktion können wir mit Lambda nun direkt einsetzen:
In [23]:
list(map(lambda x: (x * 13)/100, a))
Out[23]:
Allerdings gibt es sehr unterschiedliche Meinungen darüber, ob auf diese Weise guter Code entsteht. Ich finde diesen Ratschlag anz gut:
1) Geben Sie alle Unicode-Zeichen zwischen 34 und 250 aus und geben Sie alle aus, die keine Buchstaben oder Zahlen sind
2) Wie könnte man alle Dateien mit der Endung *.txt in einem Unterverzeichnis hintereinander ausgeben?
3) Schauen Sie sich in der Python-Dokumentation die Funktionen sort und itemgetter an. Wie kann man diese so kombinieren, dass man damit ein Dictionary nach dem value sortieren kann. (no stackoverflow :-)
In [ ]:
In [24]:
#zählt die Vokale eines strings
def cv(word):
return sum([1 for a in word if a in "aeiouAEIOUÄÖÜäöü"])
a = "Dies ist eine Lüge, oder nicht?"
[cv(w) for w in a.split()]
Out[24]:
In [25]:
#uppeditys the string word
def upper(word):
return word.upper()
a = ["dies", "ist", "Ein", "satz"]
list(map(upper, a))
Out[25]:
Aufgabe 3
In [26]:
def cv(word):
return sum([1 for a in word if a in "aeiouAEIOUÄÖÜäöü"])
a = "Dies ist eine Lüge, oder nicht?"
list(map(cv, a.split()))
Out[26]:
In [27]:
import re
#returns True if word is a function word
def is_no_function_word(word):
f_words = ["der", "die", "das", "ich", "du", "er", "sie", "es", "wir", "ihr", "dass", "ist", "hat", "auch", "und", "nicht"]
if word.lower() in f_words:
return False
else:
return True
text = """Ich denke auch, dass ist nicht schlimm. Er hat es nicht gemerkt und das ist gut.
Und überhaupt: es ist auch seine Schuld. Ehrlich, das ist wahr."""
list(filter(is_no_function_word, re.findall("\w+", text)))
Out[27]:
In [ ]: