Liste Verständnis, ohne [ ... ] in Python
Beitritt eine Liste:
>>> ''.join([ str(_) for _ in xrange(10) ])
'0123456789'
join
müssen ein durchsuchbar.
Offenbar join
's argument ist [ str(_) for _ in xrange(10) ]
, und es ist ein list comprehension.
Schau mal hier:
>>>''.join( str(_) for _ in xrange(10) )
'0123456789'
Nun join
's argument ist nur str(_) for _ in xrange(10)
keine []
, aber das Ergebnis ist das gleiche.
Warum? Tut str(_) for _ in xrange(10)
produzieren auch eine Liste oder ein durchsuchbar?
- Ich könnte mir vorstellen, dass
join
ist wahrscheinlich in C geschrieben und läuft somit wesentlich schneller als eine list comprehension... Test-Zeit! - Offenbar, lese ich deine Frage völlig falsch. Es scheint wieder ein generator für mich...
- Nur eine Anmerkung:
_
hat keine Besondere Bedeutung, es ist eine normale Variablen-Namen. Es wird oft als Wegwerf-Namen, aber das ist nicht der Fall (die variable). Ich würde vermeiden Sie es in einen code (auf diese Weise zumindest).
InformationsquelleAutor Alcott | 2012-01-30
Schreibe einen Kommentar Antworten abbrechen
Du musst angemeldet sein, um einen Kommentar abzugeben.
Dies wird als eine generator-Ausdruck, und erklärt in PEP 289.
Der Hauptunterschied zwischen generator-Ausdrücke und-Liste Verstehens ist, dass die ehemaligen nicht-erstellen der Liste im Speicher.
Beachten Sie, dass es einen Dritten Weg, der Ausdruck geschrieben:
( str(_) for _ in xrange(10) )
. Aber ich war verwirrt, warum die()
können sein weggelassen, injoin
, das heißt, der code sollte wie`.join( (str(_) for _ in xrange(10)) ), richtig?Den anderen Befragten richtig beantworten, die Sie entdeckt hatte, eine generator-Ausdruck (die eine notation ähnlich der Liste Verstehens, aber ohne die umgebenden eckigen Klammern).
Im Allgemeinen, genexps (wie Sie liebevoll genannt wird) sind mehr Speicher effizient und schneller als Liste Verstehens.
JEDOCH der Fall
''.join()
eine Liste Verständnis ist sowohl schneller und mehr Speicher effizient. Der Grund dafür ist, dass join muss zwei Durchgänge über die Daten, so muss man eigentlich eine echte Liste. Wenn Sie es geben, kann es direkt mit Ihrer Arbeit beginnen. Wenn man es genexp statt, es kann nicht anfangen zu arbeiten, bis er baut eine neue Liste im Speicher durch ausführen der genexp bis zur Erschöpfung:Das gleiche Ergebnis gilt, wenn der Vergleich itertools.imap versus Karte:
"".join(l)
. Ich benutze timeit einrichten, uml
entweder[str(n) for n in xrange(1000)]
oder(x for x in [str(n) for n in xrange(1000)])
. Ergebnisse: 21.7 usec und 1,55 usec, beziehungsweise.iter([str(n) for n in xrange(1000)])
ist noch schneller: 0.87 usec.join
, ich habe alles außer"".join(l)
im setup-Anweisung. Und darin liegt das problem -- die genexp war erschöpft, auf die erste Schleife, so dass die nächste 999999 mal trat er eine leere genexp. Kein Wunder, es war schnell.''.join()
braucht 2 Pässe über den iterator erstellen Sie eine Zeichenfolge?Dein zweites Beispiel verwendet ein generator-Ausdruck anstatt einer Liste erfassen. Der Unterschied ist, dass mit der list-comprehension, die Liste ist vollständig errichtet und übergeben
.join()
. Mit der generator-Ausdruck, Objekte werden erzeugt und verbraucht.join()
. Letztere benötigt weniger Speicher und ist grundsätzlich schneller.Wie es passiert, die Liste Konstruktor wird gerne verbrauchen jede durchsuchbar, darunter ein generator-Ausdruck. Also:
ist nur "syntaktischer Zucker" für:
In anderen Worten, eine Liste Verständnis ist nur ein generator-Ausdruck, verwandelte sich in eine Liste.
[str(x) for x in xrange(1000)]
: 262 usec,list(str(x) for x in xrange(1000))
: 304 usec.seq = PySequence_Fast(orig, "");
- und das ist der einzige Grund, Iteratoren laufen langsamer als die von Listen oder Tupeln, die beim aufrufen str.join(). Sie sind willkommen zum start einer chat-wenn Sie möchten, dass Ihr weiter diskutieren (ich bin der Autor von PEP 289, der Schöpfer der LIST_APPEND opcode, und derjenige, optimiert die list () - Konstruktor, also habe ich einige Vertrautheit mit dem Thema).list(*generator expression*)
. Und alle, die ich kannte, war es auch der Artikel, den ich erwähnt in den Kommentaren. So mein wissen über das Thema ist eher oberflächlich und aus fast der Maxime, die Liste Verstehens in Python 2.x schneller als generator-Ausdrücke. Und Tat nichts, ich weiß, dass''.join()
erfordert die Länge des Objekts, bevor es möglicherweise konstruieren die Zeichenfolge ist und dass in diesem besonderen Fall ist es der Hauptgrund der Verlangsamung.''.join()
besser aus mit der Liste Verstehens als generator Ausdruck.PySequence_Fast(...)
ist fast das gleiche wietuple(...)
oderlist(...)
(je nach Objekt geliefert als parameter). Wenn wir also rufen''.join(*generator expression*)
, die gen.Ausdruck umgewandelt werden, um Tupel. Es ist also fast das gleiche wie''.join(tuple(*generator expression*))
. Aber''.join(*list comprehension*)
ist fast das gleiche wie''.join(list(*generator expression*))
. Der einzige Unterschied zwischen den letzten 2 ist die ehemalige implementiert ist ein bisschen anders, so arbeitet Sie schneller und mit Auslaufen.''.join(*generator expression*)
sich herausstellt, führen fast die gleichen Vorgänge, die von''.join(*list comprehension*)
nur mit dem Unterschied, dass*list comprehension*
erstellt eine Liste, bevor es gesendet, die als parameterjoin
, und*generator expression*
wird verwendet, um ein Tupel erst nachdem es empfangenjoin
fordertPySequence_Fast
auf Sie. Bin ich richtig in meinem denken?x if isinstance(x, (list, tuple)) else list(x)
. In anderen Worten, wenn das argument bereits eine Liste oder Tupel, braucht er nicht zu tun, Arbeit überhaupt. Dies unterscheidet sich vonlist(x)
denen macht immer eine neue Liste.Wie erwähnt, ist es ein generator-Ausdruck.
Aus der Dokumentation:
Wenn es in Klammern, aber nicht Klammern, es ist technisch einen generator-Ausdruck. Generator-Ausdrücke, die eingeführt wurden in Python 2.4.
http://wiki.python.org/moin/Generators
Den Teil nach der Verknüpfung
( str(_) for _ in xrange(10) )
ist, durch sich selbst, einen generator-Ausdruck. Sie könnten etwas tun wie:und es bedeutet genau das gleiche, was, die Sie schrieb in der zweiten oben genannten Fall.
Generatoren haben einige sehr interessante Eigenschaften, nicht zuletzt von denen ist, dass Sie am Ende nicht die Zuweisung einer ganzen Liste, wenn Sie es nicht benötigen. Stattdessen eine Funktion wie join "Pumpen" die Elemente aus der generator-Ausdruck ein zu einer Zeit, zu tun, Ihre Arbeit auf der kleinen zwischenteilen.
In Ihrer speziellen Beispiele, die Liste und den generator wahrscheinlich nicht durchführen, furchtbar anders, aber im Allgemeinen bin ich lieber mit generator Ausdrücke (und auch die generator-Funktionen) Wann immer ich kann, vor allem, weil es ist äußerst selten für einen generator werden langsamer als eine vollständige Liste Materialisierung.
Das ist ein generator, sondern als eine Liste Verständnis. Generatoren sind auch iterables, aber anstatt die gesamte Liste zuerst, dann übergeben Sie es zu verbinden, es geht jeder Wert in der xrange eins nach dem anderen, die können sehr viel effizienter.
Dem argument zu Ihrem zweiten
join
nennen, ist ein generator-Ausdruck. Es produziert ein durchsuchbar.