Wenn die Antworten hier nicht ausreichen, habe ich sie hier gebloggt
telliott99
7
Obwohl diese Technik sehr faszinierend ist, muss sie gegen den Kernwert "Lesbarkeit" von Python verstoßen!
Demis
Antworten:
108
iter()ist ein Iterator über eine Sequenz. [x] * nerzeugt eine Liste mit einer nMenge von x, dh einer Liste der Länge n, in der sich jedes Element befindet x. *argentpackt eine Sequenz in Argumente für einen Funktionsaufruf. Daher übergeben Sie denselben Iterator dreimal an zip()und er zieht jedes Mal ein Element aus dem Iterator.
Gut zu wissen: Wenn ein Iterator ein Element yield(= returns) ist, können Sie sich dieses Element als "verbraucht" vorstellen. Wenn der Iterator das nächste Mal aufgerufen wird, ergibt er das nächste "nicht verbrauchte" Element.
Winklerrr
46
Die anderen tollen Antworten und Kommentare erklären gut die Rolle des Auspackens von Argumenten und von zip () .
Wie Ignacio und Ujukatzel sagen, gehen Sie zu zip()drei Verweisen auf denselben Iterator über und erstellenzip() aus jedem Verweis auf den Iterator 3-Tupel der Ganzzahlen - in der Reihenfolge -:
Und da Sie nach einem ausführlicheren Codebeispiel fragen:
chunk_size =3
L =[1,2,3,4,5,6,7,8,9]# iterate over L in steps of 3for start in range(0,len(L),chunk_size):# xrange() in 2.x; range() in 3.x
end = start + chunk_size
print L[start:end]# three-item chunks
Folgen Sie den Werten von startund end:
[0:3)#[1,2,3][3:6)#[4,5,6][6:9)#[7,8,9]
FWIW, Sie können das gleiche Ergebnis map()mit einem anfänglichen Argument von erhalten None:
Ich denke, eine Sache, die in allen Antworten übersehen wird (wahrscheinlich offensichtlich für diejenigen, die mit Iteratoren vertraut sind), aber für andere nicht so offensichtlich ist:
Da wir denselben Iterator haben, wird er verbraucht und die restlichen Elemente werden von der Zip-Datei verwendet. Wenn wir also einfach die Liste und nicht den Iter verwenden, z.
l = range(9)
zip(*([l]*3))# note: not an iter here, the lists are not emptied as we iterate # output [(0,0,0),(1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5),(6,6,6),(7,7,7),(8,8,8)]
Wenn Sie den Iterator verwenden, werden die Werte eingeblendet und bleiben nur verfügbar, sodass für zip, sobald 0 verbraucht ist, 1 verfügbar ist und dann 2 und so weiter. Eine sehr subtile Sache, aber ziemlich klug !!!
+1, Du hast mich gerettet! Ich kann nicht glauben, dass andere Antworten dieses wichtige Detail übersprungen haben, vorausgesetzt, jeder weiß das. Können Sie auf eine Dokumentation verweisen, die diese Informationen enthält?
Snehasish Karmakar
9
iter(s) Gibt einen Iterator für s zurück.
[iter(s)]*n macht eine Liste von n mal dem gleichen Iterator für s.
Dabei zip(*[iter(s)]*n)wird ein Element aus allen drei Iteratoren der Reihe nach aus der Liste extrahiert. Da alle Iteratoren dasselbe Objekt sind, wird die Liste nur in Blöcke von gruppiert n.
Nicht 'n Iteratoren derselben Liste', sondern 'n mal dasselbe Iteratorobjekt'. Verschiedene Iteratorobjekte haben keinen gemeinsamen Status, selbst wenn sie zur selben Liste gehören.
Thomas Wouters
Danke, korrigiert. Das habe ich zwar "gedacht", aber etwas anderes geschrieben.
Sttwister
6
Ein Ratschlag für die Verwendung von zip auf diese Weise. Ihre Liste wird abgeschnitten, wenn ihre Länge nicht gleichmäßig teilbar ist. Um dies zu umgehen , können Sie entweder itertools.izip_longest verwenden, wenn Sie Füllwerte akzeptieren können. Oder Sie könnten so etwas verwenden:
Es ist wahrscheinlich einfacher zu sehen, was im Python-Interpreter passiert oder ipythonmit n = 2:
In[35]:[iter("ABCDEFGH")]*2Out[35]:[<iterator at 0x6be4128>,<iterator at 0x6be4128>]
Wir haben also eine Liste von zwei Iteratoren, die auf dasselbe Iteratorobjekt zeigen. Denken Sie daran, dass iterein Objekt ein Iteratorobjekt zurückgibt und in diesem Szenario aufgrund des *2syntaktischen Python-Zuckers zweimal derselbe Iterator ist . Iteratoren laufen auch nur einmal.
Ferner zipnimmt eine beliebige Anzahl von Iterables ( Sequenzen sind Iterables ) und erstellt Tupel aus i'th Elemente von jedem der Eingangssequenzen. Da in unserem Fall beide Iteratoren identisch sind, verschiebt zip denselben Iterator zweimal für jedes 2-Element-Tupel der Ausgabe.
In[41]: help(zip)Help on built-in function zip in module __builtin__:
zip(...)
zip(seq1 [, seq2 [...]])->[(seq1[0], seq2[0]...),(...)]Return a list of tuples, where each tuple contains the i-th element
from each of the argument sequences.The returned list is truncated
in length to the length of the shortest argument sequence.
Der Operator unpacking ( *) stellt sicher, dass die Iteratoren bis zur Erschöpfung ausgeführt werden. In diesem Fall ist dies so lange der Fall, bis nicht mehr genügend Eingaben vorhanden sind, um ein Tupel mit zwei Elementen zu erstellen.
Dies kann auf jeden Wert von erweitert werden nund zip(*[iter(s)]*n)funktioniert wie beschrieben.
Tut mir leid, dass ich langsam bin. Aber könnten Sie den "gleichen Iterator zweimal aufgrund des syntaktischen * 2-Python-Zuckers erklären? Iteratoren werden auch nur einmal ausgeführt." Teil bitte? Wenn ja, warum ist das Ergebnis nicht [("A", "A") ....]? Vielen Dank.
Bowen Liu
@BowenLiu *ist nur eine bequeme Möglichkeit, ein Objekt zu duplizieren. Versuchen Sie es mit Skalaren und dann mit Listen. Versuchen Sie auch print(*zip(*[iter("ABCDEFG")]*2))vs print(*zip(*[iter("ABCDEFG"), iter("ABCDEFG")])). Zerreißen Sie dann die beiden in kleinere Schritte, um zu sehen, was die tatsächlichen Iteratorobjekte in den beiden Anweisungen sind.
Antworten:
iter()
ist ein Iterator über eine Sequenz.[x] * n
erzeugt eine Liste mit einern
Menge vonx
, dh einer Liste der Längen
, in der sich jedes Element befindetx
.*arg
entpackt eine Sequenz in Argumente für einen Funktionsaufruf. Daher übergeben Sie denselben Iterator dreimal anzip()
und er zieht jedes Mal ein Element aus dem Iterator.quelle
yield
(=return
s) ist, können Sie sich dieses Element als "verbraucht" vorstellen. Wenn der Iterator das nächste Mal aufgerufen wird, ergibt er das nächste "nicht verbrauchte" Element.Die anderen tollen Antworten und Kommentare erklären gut die Rolle des Auspackens von Argumenten und von zip () .
Wie Ignacio und Ujukatzel sagen, gehen Sie zu
zip()
drei Verweisen auf denselben Iterator über und erstellenzip()
aus jedem Verweis auf den Iterator 3-Tupel der Ganzzahlen - in der Reihenfolge -:Und da Sie nach einem ausführlicheren Codebeispiel fragen:
Folgen Sie den Werten von
start
undend
:FWIW, Sie können das gleiche Ergebnis
map()
mit einem anfänglichen Argument von erhaltenNone
:Weitere Informationen zu
zip()
undmap()
: http://muffinresearch.co.uk/archives/2007/10/16/python-transposing-lists-with-map-and-zip/quelle
Ich denke, eine Sache, die in allen Antworten übersehen wird (wahrscheinlich offensichtlich für diejenigen, die mit Iteratoren vertraut sind), aber für andere nicht so offensichtlich ist:
Da wir denselben Iterator haben, wird er verbraucht und die restlichen Elemente werden von der Zip-Datei verwendet. Wenn wir also einfach die Liste und nicht den Iter verwenden, z.
Wenn Sie den Iterator verwenden, werden die Werte eingeblendet und bleiben nur verfügbar, sodass für zip, sobald 0 verbraucht ist, 1 verfügbar ist und dann 2 und so weiter. Eine sehr subtile Sache, aber ziemlich klug !!!
quelle
iter(s)
Gibt einen Iterator für s zurück.[iter(s)]*n
macht eine Liste von n mal dem gleichen Iterator für s.Dabei
zip(*[iter(s)]*n)
wird ein Element aus allen drei Iteratoren der Reihe nach aus der Liste extrahiert. Da alle Iteratoren dasselbe Objekt sind, wird die Liste nur in Blöcke von gruppiertn
.quelle
Ein Ratschlag für die Verwendung von zip auf diese Weise. Ihre Liste wird abgeschnitten, wenn ihre Länge nicht gleichmäßig teilbar ist. Um dies zu umgehen , können Sie entweder itertools.izip_longest verwenden, wenn Sie Füllwerte akzeptieren können. Oder Sie könnten so etwas verwenden:
Verwendung:
Drucke:
quelle
itertools
Rezepten dokumentiert : docs.python.org/2/library/itertools.html#recipesgrouper
. Keine Notwendigkeit, das Rad neu zu erfindenEs ist wahrscheinlich einfacher zu sehen, was im Python-Interpreter passiert oder
ipython
mitn = 2
:Wir haben also eine Liste von zwei Iteratoren, die auf dasselbe Iteratorobjekt zeigen. Denken Sie daran, dass
iter
ein Objekt ein Iteratorobjekt zurückgibt und in diesem Szenario aufgrund des*2
syntaktischen Python-Zuckers zweimal derselbe Iterator ist . Iteratoren laufen auch nur einmal.Ferner
zip
nimmt eine beliebige Anzahl von Iterables ( Sequenzen sind Iterables ) und erstellt Tupel aus i'th Elemente von jedem der Eingangssequenzen. Da in unserem Fall beide Iteratoren identisch sind, verschiebt zip denselben Iterator zweimal für jedes 2-Element-Tupel der Ausgabe.Der Operator unpacking (
*
) stellt sicher, dass die Iteratoren bis zur Erschöpfung ausgeführt werden. In diesem Fall ist dies so lange der Fall, bis nicht mehr genügend Eingaben vorhanden sind, um ein Tupel mit zwei Elementen zu erstellen.Dies kann auf jeden Wert von erweitert werden
n
undzip(*[iter(s)]*n)
funktioniert wie beschrieben.quelle
*
ist nur eine bequeme Möglichkeit, ein Objekt zu duplizieren. Versuchen Sie es mit Skalaren und dann mit Listen. Versuchen Sie auchprint(*zip(*[iter("ABCDEFG")]*2))
vsprint(*zip(*[iter("ABCDEFG"), iter("ABCDEFG")]))
. Zerreißen Sie dann die beiden in kleinere Schritte, um zu sehen, was die tatsächlichen Iteratorobjekte in den beiden Anweisungen sind.