Gibt es eine syntaktisch präzisere Art, Folgendes zu schreiben?
gen = (i for i in xrange(10))
index = 5
for i, v in enumerate(gen):
if i is index:
return v
Es scheint fast natürlich, dass ein Generator einen gen[index]
Ausdruck haben sollte, der als Liste fungiert, aber funktional mit dem obigen Code identisch ist.
is
in dieser Situation (oder in vielen Situationen überhaupt).is
dient zum Vergleich der Identität, nicht der Gleichheit. Du willst==
. Dies wird in diesem Fall wahrscheinlich funktionieren, jedoch nur durch Zufall und Implementierungsdetails.index
Objekt__eq__
in solchen Fällen implementiert wird? (Dies kommt vom Thema ab ...)1000 is 500 + 500
Sie es (wahrscheinlich)False
. Siehe zum Beispiel stackoverflow.com/questions/306313/…Antworten:
Eine Methode wäre zu verwenden
itertools.islice
>>> gen = (x for x in range(10)) >>> index = 5 >>> next(itertools.islice(gen, index, None)) 5
quelle
Sie können dies am
count
Beispiel eines Generators tun :from itertools import islice, count next(islice(count(), n, n+1))
quelle
AttributeError: 'itertools.islice' object has no attribute 'next'
in 3.3.next
in Python 3x zu__next__()
, dhislice(count, n, n=1).__next__()
next(islice(count(), n, n+1))
.next(islice(count(), n, None))
.Ich denke, der beste Weg ist:
next(x for i,x in enumerate(it) if i==n)
(Wo
it
ist dein Iterator undn
ist der Index)Sie müssen weder einen Import hinzufügen (wie bei den verwendeten Lösungen
itertools
) noch alle Elemente des Iterators gleichzeitig in den Speicher laden (wie bei den verwendeten Lösungenlist
).Hinweis 1: Diese Version gibt einen
StopIteration
Fehler aus, wenn Ihr Iterator weniger als n Elemente enthält. Wenn SieNone
stattdessen erhalten möchten , können Sie verwenden:next((x for i,x in enumerate(it) if i==n), None)
Hinweis 2: Der Anruf an enthält keine Klammern
next
. Dies ist kein Listenverständnis, sondern ein Generatorverständnis, das den ursprünglichen Iterator nicht weiter als bis zu seinem n-ten Element verbraucht.quelle
Ich würde gegen die Versuchung argumentieren, Generatoren wie Listen zu behandeln. Der einfache, aber naive Ansatz ist der einfache Einzeiler:
gen = (i for i in range(10)) list(gen)[3]
Aber denken Sie daran, Generatoren sind keine Listen. Sie speichern ihre Zwischenergebnisse nirgendwo, sodass Sie nicht rückwärts gehen können. Ich werde das Problem anhand eines einfachen Beispiels in der Python-Antwort demonstrieren:
>>> gen = (i for i in range(10)) >>> list(gen)[3] 3 >>> list(gen)[3] Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: list index out of range
Sobald Sie einen Generator durchlaufen, um den n-ten Wert in der Sequenz zu erhalten, befindet sich der Generator jetzt in einem anderen Zustand. Wenn Sie versuchen, den n-ten Wert erneut abzurufen, erhalten Sie ein anderes Ergebnis, das wahrscheinlich zu einem Fehler in Ihrem führt Code.
Schauen wir uns ein anderes Beispiel an, das auf dem Code aus der Frage basiert.
Man würde zunächst erwarten, dass das Folgende
4
zweimal gedruckt wird.gen = (i for i in range(10)) index = 4 for i, v in enumerate(gen): if i == index: answer = v break print(answer) for i, v in enumerate(gen): if i == index: answer = v break print(answer)
aber tippe dies in die Antwort und du erhältst:
>>> gen = (i for i in range(10)) >>> index = 4 >>> for i, v in enumerate(gen): ... if i == index: ... answer = v ... break ... >>> print(answer) 4 >>> for i, v in enumerate(gen): ... if i == index: ... answer = v ... break ... >>> print(answer) 9
Viel Glück beim Aufspüren dieses Fehlers.
BEARBEITEN:
Wenn der Generator unendlich lang ist, können Sie ihn nicht einmal in eine Liste konvertieren. Der Ausdruck
list(gen)
wird niemals enden.Es gibt eine Möglichkeit, einen träge ausgewerteten Caching-Wrapper um einen unendlichen Generator zu legen, damit er wie eine unendlich lange Liste aussieht, in die Sie nach Belieben indizieren können. Dies verdient jedoch eine eigene Frage und Antwort und hätte erhebliche Auswirkungen auf die Leistung.
quelle
Das erste, was mir in den Sinn kam, war:
gen = (i for i in xrange(10)) index = 5 for i, v in zip(range(index), gen): pass return v
quelle
Wenn dies zum
n
Zeitpunkt des Authorings bekannt ist, können Sie die Destrukturierung verwenden. zB um den 3. Artikel zu bekommen:>>> [_, _, third, *rest] = range(10) >>> third 2 >>> rest [3, 4, 5, 6, 7, 8, 9]
quelle
Am besten zu verwenden ist: Beispiel:
a = gen values ('a','c','d','e')
Die Antwort lautet also:
a = list(a) -> this will convert the generator to a list (it will store in memory)
Wenn Sie dann einen bestimmten Index erstellen möchten, werden Sie:
a[INDEX] -> and you will able to get the value its holds
Wenn Sie nur die Anzahl kennen oder Vorgänge ausführen möchten, die nicht im Speicher gespeichert werden müssen, gilt Folgendes:
a = sum(1 in i in a)
-> Hiermit wird die Anzahl der Objekte gezählt, über die Sie verfügenIch hoffe, ich habe es einfacher gemacht.
quelle
Vielleicht sollten Sie einen tatsächlichen Anwendungsfall näher erläutern.
>>> gen = xrange(10) >>> ind=5 >>> gen[ind] 5
quelle
xrange(10)
zu(i for i in xrange(10))
. Es stellt sich heraus, dass diese Syntax funktioniert,xrange
da es sich nicht wirklich um einen Generator handelt ...xrange
älter als Generatoren und gibt ein xrange-Objekt zurück, das tatsächlich das vollständige Sequenzprotokoll implementiert.