Nach den Funktionen zip, map und lambda, werfe ich heute einen Blick auf die Funktion filter. Auf den ersten Blick macht diese Funktion das gleiche wie map, nämlich eine Funktion auf eine Liste werfen. Es gibt jedoch Unterschiede.
Angenommen, wir haben eine Liste mit dem Alter von Personen. Nun wollen wir wissen, welche Personen volljährig sind. Hier ist der Code:
def volljaehrig(x):
if x >= 18: return True
else: return False
alter = [11,73,18,12,20,9,31]
list(filter(volljaehrig, alter))
[73, 18, 20, 31]
Wir haben eine Liste mit Zahlen. Dann rufen wir den Befehl filter auf und übergeben eine Funktion und die Liste. Nun wird die Funktion auf jedes Element der Liste angewendet. Die Funktion enthält eine Bedingungen ( >=18 ) und liefert entweder True oder False zurück. Diese Rückgabewerte entscheiden über die Elemente der neuen Liste, die filter zurückgibt. Es werden nur diejenigen Elemente aufgenommen, für die die Bedingung True ist.
Im Gegensatz dazu wendet map die Funktion auf jedes Element der Liste an und das Ergebnis ist Bestandteil der neuen Liste. Ausserdem kann map mehrere Listen entgegennehmen, während filter nur eine empfängt. Somit ist map allgemeiner als filter, das nur eine Liste erwartet. Ausserdem muss die Entscheidungsfunktion einen Boolschen Wert zurückgeben.
Filter ist in C implementiert und damit wesentlicher schneller, als würde man dasselbe mit einer For-Schleife machen.
Wie erwartet ist eine list comprehension etwa um Faktor 2 schneller.
Hier ein Vergleich der mesiten denkbaren Methoden und Kombinationen: naturalnet.de/~nik/filter_test.py
Stellt sich raus: Teuer sind die Funktionsdefinition und das Aufrufen der Funktion, und zwar so teuer, dass der Vorteil der filter-Funktion keinerlei Rolle spielt. Wie auch? Die Argumentation, das sei in C implementiert, ist ein Fehlschluss: Natürlich ist filter in C implementiert, genauso wie die for-Schleife. Aber was soll das bringen, wenn der C-Code lediglich in eine Python-Funktion dispatcht?
(Achtung: Der Geschwindigkeitsunterschied beim filter hier im Benchmark kommt vom
append
, das auf eienr Liste langsam ist, nicht von der for-Schleife).Also: Um den C-Vorteil auszunutzen, muss es eine List-Comprehension sein.
filter ist insbesondere dann stark, wenn man es mti einem Generator direkt benutzt. Und es sei angemerkt, dass filter auch einen Generator zurückgibt. Wenn man über das Ergebnis iteriert, sollte man nicht erst zu einer Liste casten.