986 Stimmen

Listenverständnis vs. Karte

Gibt es einen Grund, die Verwendung von map() über das Listenverständnis oder umgekehrt? Ist eine der beiden Methoden generell effizienter oder gilt sie als pythonischer als die andere?

869voto

Alex Martelli Punkte 805329

map kann in einigen Fällen mikroskopisch schneller sein (wenn Sie NICHT ein Lambda für den Zweck erstellen, sondern dieselbe Funktion in map und einer Listcomp verwenden). List comprehensions können in anderen Fällen schneller sein und die meisten (nicht alle) Pythonisten halten sie für direkter und klarer.

Ein Beispiel für den winzigen Geschwindigkeitsvorteil von map, wenn genau dieselbe Funktion verwendet wird:

$ python -m timeit -s'xs=range(10)' 'map(hex, xs)'
100000 loops, best of 3: 4.86 usec per loop
$ python -m timeit -s'xs=range(10)' '[hex(x) for x in xs]'
100000 loops, best of 3: 5.58 usec per loop

Ein Beispiel dafür, wie sich der Leistungsvergleich komplett umkehrt, wenn map ein Lambda benötigt:

$ python -m timeit -s'xs=range(10)' 'map(lambda x: x+2, xs)'
100000 loops, best of 3: 4.24 usec per loop
$ python -m timeit -s'xs=range(10)' '[x+2 for x in xs]'
100000 loops, best of 3: 2.32 usec per loop

115voto

user541686 Punkte 196656

Python 2: Sie sollten Folgendes verwenden map y filter anstelle von Listenauffassungen.

Eine Zielsetzung Der Grund, warum Sie sie bevorzugen sollten, auch wenn sie nicht "pythonisch" sind, ist folgender:
Sie erfordern Funktionen/Lambdas als Argumente, die einen neuen Anwendungsbereich einführen .

Das hat mich schon mehr als einmal erwischt:

for x, y in somePoints:
    # (several lines of code here)
    squared = [x ** 2 for x in numbers]
    # Oops, x was silently overwritten!

aber wenn ich stattdessen gesagt hätte:

for x, y in somePoints:
    # (several lines of code here)
    squared = map(lambda x: x ** 2, numbers)

dann wäre alles in Ordnung gewesen.

Man könnte sagen, ich sei dumm, weil ich denselben Variablennamen im selben Bereich verwendet habe.

Ich war es nicht. Der Code war ursprünglich in Ordnung - die beiden x s nicht in denselben Bereich fallen.
Erst nachdem ich umgezogen Ich habe den inneren Block in einen anderen Abschnitt des Codes verschoben, als das Problem auftrat (lies: Problem während der Wartung, nicht während der Entwicklung), und ich habe es nicht erwartet.

Ja, wenn Sie diesen Fehler nie machen dann sind Listenauffassungen eleganter.
Aber aus persönlicher Erfahrung (und weil ich gesehen habe, dass andere denselben Fehler gemacht haben), habe ich es oft genug erlebt, dass ich denke, dass es den Schmerz nicht wert ist, den man erleiden muss, wenn sich diese Fehler in den Code einschleichen.

Schlussfolgerung:

Verwenden Sie map y filter . Sie verhindern subtile, schwer zu diagnostizierende Fehler im Zusammenhang mit dem Anwendungsbereich.

Nebenbei bemerkt:

Vergessen Sie nicht, die Verwendung von imap y ifilter (in itertools ), wenn sie für Ihre Situation geeignet sind!

54voto

raek Punkte 1956

Eigentlich, map und List Comprehensions verhalten sich in der Sprache Python 3 ganz anders. Werfen Sie einen Blick auf das folgende Python 3-Programm:

def square(x):
    return x*x
squares = map(square, [1, 2, 3])
print(list(squares))
print(list(squares))

Man könnte erwarten, dass die Zeile "[1, 4, 9]" zweimal ausgegeben wird, aber stattdessen wird "[1, 4, 9]" gefolgt von "[]" ausgegeben. Das erste Mal, dass Sie sich squares scheint sie sich wie eine Folge von drei Elementen zu verhalten, beim zweiten Mal jedoch wie eine leere Folge.

In der Sprache Python 2 map gibt eine einfache alte Liste zurück, so wie es Listenversteher in beiden Sprachen tun. Der springende Punkt ist, dass der Rückgabewert von map in Python 3 (und imap in Python 2) ist keine Liste - es ist ein Iterator!

Bei der Iteration über einen Iterator werden die Elemente verbraucht, anders als bei der Iteration über eine Liste. Aus diesem Grund squares sieht im letzten Teil leer aus print(list(squares)) Linie.

Zusammengefasst:

  • Beim Umgang mit Iteratoren muss man bedenken, dass sie zustandsabhängig sind und sich beim Durchlaufen verändern.
  • Listen sind besser vorhersehbar, da sie sich nur ändern, wenn sie explizit verändert werden; sie sind Container .
  • Und ein Bonus: Zahlen, Strings und Tupel sind sogar noch berechenbarer, da sie sich überhaupt nicht ändern können; sie sind Werte .

22voto

Andz Punkte 1266

Hier ist ein möglicher Fall:

map(lambda op1,op2: op1*op2, list1, list2)

gegen:

[op1*op2 for op1,op2 in zip(list1,list2)]

Ich vermute, dass zip() ein unglücklicher und unnötiger Overhead ist, den Sie in Kauf nehmen müssen, wenn Sie darauf bestehen, List Comprehensions anstelle der Map zu verwenden. Es wäre großartig, wenn jemand dies klärt, ob positiv oder negativ.

21voto

Mike McKerns Punkte 30236

Wenn Sie vorhaben, asynchronen, parallelen oder verteilten Code zu schreiben, werden Sie wahrscheinlich die map über ein Listenverständnis - da die meisten asynchronen, parallelen oder verteilten Pakete eine map Funktion zum Überladen von Python's map . Dann wird durch die Übergabe der entsprechenden map Funktion mit dem Rest Ihres Codes zu verbinden, müssen Sie Ihren ursprünglichen seriellen Code möglicherweise nicht ändern, um ihn parallel laufen zu lassen (usw.).

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X