Beitritt zu einer Liste:
>>> ''.join([ str(_) for _ in xrange(10) ])
'0123456789'
join
muss eine iterable nehmen.
Anscheinend ist join
das Argument [ str(_) for _ in xrange(10) ]
, und es ist ein Listenverständnis .
Schau dir das an:
>>>''.join( str(_) for _ in xrange(10) )
'0123456789'
Nun, join
das Argument ist einfach str(_) for _ in xrange(10)
, nein []
, aber das Ergebnis ist das gleiche.
Warum? Erzeugt str(_) for _ in xrange(10)
auch eine Liste oder eine iterable?
python
list-comprehension
Alcott
quelle
quelle
join
das höchstwahrscheinlich in C geschrieben ist und daher viel schneller läuft als ein Listenverständnis ... Testzeit!_
hat keine besondere Bedeutung, es ist ein regulärer Variablenname. Es wird oft als Wegwerfname verwendet, aber dies ist nicht der Fall (Sie verwenden die Variable). Ich würde es vermeiden, es in einem Code zu verwenden (zumindest auf diese Weise).Antworten:
Dies wird als Generatorausdruck bezeichnet und in PEP 289 erläutert .
Der Hauptunterschied zwischen Generatorausdrücken und Listenverständnis besteht darin, dass erstere die Liste nicht im Speicher erstellen.
Beachten Sie, dass es eine dritte Möglichkeit gibt, den Ausdruck zu schreiben:
quelle
( str(_) for _ in xrange(10) )
. Aber ich war verwirrt darüber, warum das()
weggelassen werden kannjoin
, was bedeutet, dass der Code wie '' '.join ((str (_) für _ in xrange (10))) sein sollte, richtig?tup = 1, 2, 3; print(tup)
. In diesem Sinne wird durch die Verwendungfor
als Teil eines Ausdrucks der Generator erstellt, und die Klammern dienen nur dazu, ihn von einer falsch geschriebenen Schleife zu unterscheiden.Die anderen Befragten antworteten zu Recht, dass Sie einen Generatorausdruck entdeckt hatten (dessen Notation dem Listenverständnis ähnelt, jedoch ohne die umgebenden eckigen Klammern).
Im Allgemeinen sind Genexps (wie sie liebevoll genannt werden) speichereffizienter und schneller als Listenverständnisse.
Es ist jedoch der Fall
''.join()
, wird eine Liste Verständnis ist schneller und mehr Speicher effizienter zu gestalten . Der Grund dafür ist, dass der Join zwei Durchgänge über die Daten durchführen muss, sodass tatsächlich eine echte Liste erforderlich ist. Wenn Sie ihm einen geben, kann er sofort mit der Arbeit beginnen. Wenn Sie ihm stattdessen einen Genexp geben, kann er erst dann mit der Arbeit beginnen, wenn eine neue Liste im Speicher erstellt wurde, indem der Genexp bis zur Erschöpfung ausgeführt wird:Das gleiche Ergebnis gilt bei einem Vergleich itertools.imap gegen Karte :
quelle
''.join()
2 Durchgänge über den Iterator erforderlich sind, um eine Zeichenfolge zu erstellen?In Ihrem zweiten Beispiel wird eher ein Generatorausdruck als ein Listenverständnis verwendet. Der Unterschied besteht darin, dass mit dem Listenverständnis eine Liste vollständig erstellt und übergeben wird
.join()
. Mit dem Generatorausdruck werden Elemente einzeln generiert und von verbraucht.join()
. Letzteres benötigt weniger Speicher und ist im Allgemeinen schneller.Zufällig verwendet der Listenkonstruktor gerne alle iterierbaren Elemente, einschließlich eines Generatorausdrucks. So:
ist nur "syntaktischer Zucker" für:
Mit anderen Worten, ein Listenverständnis ist nur ein Generatorausdruck, der in eine Liste umgewandelt wird.
quelle
[str(x) for x in xrange(1000)]
262 usec ,list(str(x) for x in xrange(1000))
: 304 usec.seq = PySequence_Fast(orig, "");
und dies ist der einzige Grund, warum Iteratoren beim Aufrufen von str.join () langsamer ausgeführt werden als Listen oder Tupel. Sie können gerne einen Chat starten, wenn Sie ihn weiter diskutieren möchten (ich bin der Autor von PEP 289, der Ersteller des Opcodes LIST_APPEND, und derjenige, der den Konstruktor list () optimiert hat, also habe ich einige Vertrautheit mit dem Thema).Wie bereits erwähnt, handelt es sich um einen Generatorausdruck .
Aus der Dokumentation:
quelle
Wenn es in Parens, aber nicht in Klammern steht, ist es technisch gesehen ein Generatorausdruck. Generatorausdrücke wurden erstmals in Python 2.4 eingeführt.
http://wiki.python.org/moin/Generators
Der Teil nach dem Join
( str(_) for _ in xrange(10) )
ist für sich genommen ein Generatorausdruck. Sie könnten so etwas tun wie:und es bedeutet genau das gleiche, was Sie im zweiten Fall oben geschrieben haben.
Generatoren haben einige sehr interessante Eigenschaften, nicht zuletzt, dass sie nicht eine ganze Liste zuordnen, wenn Sie keine benötigen. Stattdessen "pumpt" eine Funktion wie "Verbinden" die Elemente einzeln aus dem Generatorausdruck und bearbeitet die winzigen Zwischenteile.
In Ihren speziellen Beispielen arbeiten Liste und Generator wahrscheinlich nicht besonders unterschiedlich, aber im Allgemeinen bevorzuge ich die Verwendung von Generatorausdrücken (und sogar Generatorfunktionen), wann immer ich kann, hauptsächlich, weil es äußerst selten ist, dass ein Generator langsamer als eine vollständige Liste ist Materialisation.
quelle
Das ist eher ein Generator als ein Listenverständnis. Generatoren sind ebenfalls iterabel, aber anstatt zuerst die gesamte Liste zu erstellen und dann an den Join zu übergeben, werden alle Werte im x-Bereich einzeln übergeben, was viel effizienter sein kann.
quelle
Das Argument für Ihren zweiten
join
Aufruf ist ein Generatorausdruck. Es erzeugt eine iterable.quelle