Hallo Habr. Oft stellt sich bei der Arbeit mit Sequenzen die Frage nach deren Entstehung. Es scheint gewohnt zu sein,
List Inclusion (List Comprehension) zu verwenden , und in Büchern wird auf die obligatorische Verwendung der integrierten
Kartenfunktion hingewiesen.
In diesem Artikel werden diese Ansätze zum Arbeiten mit Sequenzen betrachtet, die Leistung verglichen und auch ermittelt, in welchen Situationen welcher Ansatz besser ist.
Listenverständnis
Die Aufnahme von Listen ist ein in Python integrierter Mechanismus zur Listenerstellung. Er hat nur eine Aufgabe - eine Liste zu erstellen. Listeneinschluss erstellt eine Liste aus einem beliebigen iterierbaren Typ, wobei die eingehenden Werte transformiert (gefiltert) werden.
Ein Beispiel für einen einfachen Listeneinschluss zum Generieren einer Liste von Quadraten mit Zahlen von 0 bis 9:
squares = [x*x for x in range(10)]
Ergebnis:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Karte
map ist eine Funktion, die in die Sprache eingebaut ist. Es akzeptiert eine Funktion als ersten Parameter und ein iterierbares Objekt als zweiten. Gibt einen Generator (Python 3.x) oder eine Liste (Python 2.x) zurück. Ich werde Python 3 wählen.
Ein Beispiel für den Aufruf der Kartenfunktion zum Generieren einer Liste von Quadraten mit Zahlen von 0 bis 9:
squares = list(map(lambda x: x*x, range(10)))
Ergebnis:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Leistungsvergleich
Bauen ohne Funktionen
Als Experiment betrachten wir die Quadrate von Zahlen aus dem Intervall von 0 bis 9.999.999:
python -m timeit -r 10 "[x*x for x in range(10000000)]" python -m timeit -r 10 "list(map(lambda x: x*x, range(10000000)))"
Ergebnisse:
1 loop, best of 10: 833 msec per loop 1 loop, best of 10: 1.22 sec per loop
Wie Sie sehen, arbeitet die
Listenerfassungsmethode etwa 32% schneller. Demontiert ist es nicht möglich, vollständige Antworten zu erhalten, da die Kartenfunktion „die Details ihrer Arbeit zu verbergen scheint“. Dies liegt aber höchstwahrscheinlich am ständigen Aufruf der Lambda-Funktion, innerhalb derer bereits quadratische Berechnungen durchgeführt werden. Im Falle von List Comprehension müssen wir nur das Quadrat berechnen.
Bauen mit Features
Zum Vergleich betrachten wir auch die Quadrate der Zahlen, aber die Berechnungen befinden sich nun in der Funktion:
python -m timeit -r 10 -s "def pow2(x): return x*x" "[pow2(x) for x in range(10000000)]" python -m timeit -r 10 -s "def pow2(x): return x*x" "list(map(pow2, range(10000000)))"
Ergebnisse:
1 loop, best of 10: 1.41 sec per loop 1 loop, best of 10: 1.21 sec per loop
Diesmal ist die Situation umgekehrt. Die
Kartenmethode war 14% schneller. In diesem Beispiel befinden sich beide Methoden in derselben Situation. Beide müssen eine Funktion aufrufen, um das Quadrat zu berechnen. Die internen Optimierungen der Kartenfunktion ermöglichen es jedoch, bessere Ergebnisse anzuzeigen.
Was soll man wählen?
Nachfolgend finden Sie die Regel zur Auswahl der richtigen Methode:

Es kann Ausnahmen von dieser Regel geben, aber in den meisten Fällen hilft es Ihnen, die richtige Wahl zu treffen!
ist map "sicherer"?
Warum fordern viele die Verwendung von
Karten . Tatsache ist, dass die Karte in einigen Fällen tatsächlich sicherer ist als das Listenverständnis.
Zum Beispiel:
symbols = ['a', 'b', 'c'] values = [1, 2, 3] for x in symbols: print(x) squared = [x*x for x in values]
Die Ausgabe des Programms sieht wie folgt aus:
a 3 b 3 c 3
Schreiben Sie nun den gleichen Code mit
map :
symbols = ['a', 'b', 'c'] values = [1, 2, 3] for x in symbols: print(x) squared = map(lambda x: x*x, values)
Fazit:
a a b b c c
Die meisten Beobachter konnten bereits anhand der Syntax von
map feststellen, dass dies Python 2 ist. Tatsächlich gab es im zweiten Python ein ähnliches Problem beim Überschreiben von Variablen. In Python 3 wurde dieses Problem jedoch behoben und ist nicht mehr relevant.
Die oben beschriebenen Beispiele zeigen die gleichen Ergebnisse. Es mag auch den Anschein haben, dass dies ein dummer Fehler ist, und Sie werden niemals einen solchen Fehler machen. Dies kann jedoch passieren, wenn Sie einfach einen Codeblock mit einer inneren Schleife von einem anderen Block übertragen. Solch ein Fehler kann viel Zeit und Nerven kosten, um ihn zu beheben.
Fazit
Ein Vergleich ergab, dass jede der Methoden in ihrer Situation gut ist.
- Wenn Sie nicht alle berechneten Werte auf einmal benötigen (oder sie überhaupt nicht benötigen), sollten Sie sich für die Karte entscheiden . Daher fordern Sie nach Bedarf einen Teil der Daten vom Generator an, während Sie viel Speicherplatz sparen (Python 3. In Python 2 ist dies nicht sinnvoll, da map eine Liste zurückgibt).
- Wenn Sie alle Werte auf einmal berechnen müssen und die Berechnungen ohne Verwendung von Funktionen durchgeführt werden können, sollten Sie eine Auswahl in Richtung List Comprehension treffen. Wie die Ergebnisse von Experimenten zeigen, hat es einen signifikanten Leistungsvorteil.
PS: Wenn ich etwas verpasst habe, diskutiere ich es gerne mit Ihnen in den Kommentaren.