Obtenir le n-ième élément d'un générateur en Python
Est-il un plus pour la syntaxe concise façon d'écrire la suite?
gen = (i for i in xrange(10))
index = 5
for i, v in enumerate(gen):
if i is index:
return v
Il semble presque naturel que d'un générateur doit avoir un gen[index]
expression, qui agit comme une liste, mais est fonctionnellement identique au code ci-dessus.
- Vous ne voulez pas
is
dans cette situation (ou dans de nombreuses situations à tous).is
est pour la comparaison de l'identité, non pas l'égalité. Vous souhaitez==
. Ce sera sans doute dans cette instance, mais uniquement par le hasard et le détail de l'implémentation. - Depuis que je suis en utilisant des entiers, comment pourrait-il ne fonctionne pas? Est-il même bien pratique de s'attendre à ce que le
index
objet de mettre en œuvre__eq__
dans de tels cas? (Ça devient hors sujet...) - Essayez
1000 is 500 + 500
, il sera (probablement) êtreFalse
. Voir, par exemple, stackoverflow.com/questions/306313/... - +1 pour cette question. Il semble étrange qu'il n'y a pas moins verbeux-à-dire "le n-ième résultat de gen".
- Une autre possibilité est de fermetures à glissière - - - - ils gérer arbitraire des arbres, mais une liste est un arbre aussi. Voir cette mise en œuvre github.com/trivio/zipper/blob/master/tests/test_zipper.py
Vous devez vous connecter pour publier un commentaire.
une méthode serait d'utiliser
itertools.islice
5 + 1
avecNone
il travaille aussi, et lit simpleVous pourriez faire, à l'aide de
count
comme un exemple de générateur:AttributeError: 'itertools.islice' object has no attribute 'next'
en 3.3.next
à__next__()
, c'est à dire,islice(count, n, n=1).__next__()
next(islice(count(), n, n+1))
.Je pense que la meilleure façon est :
(où
it
est votre itérateur etn
est l'indice)Il ne vous obligent pas à ajouter une importation (comme les solutions à l'aide de
itertools
), ni à la charge de tous les éléments de l'itérateur en mémoire à la fois (comme les solutions à l'aide delist
).Note 1: cette version jette un
StopIteration
d'erreur si votre itérateur a moins de n éléments. Si vous souhaitez obtenirNone
au lieu de cela, vous pouvez utiliser :Note 2: Il n'y a pas de crochets à l'intérieur de l'appel à
next
. Ce n'est pas une compréhension de liste, mais un générateur de compréhension, qui ne consomme pas l'original de l'itérateur plus loin que son nième élément.Je dirais contre la tentation de traiter des générateurs comme des listes. Le simple mais approche naïve est la simple one-liner:
Mais rappelez-vous, les générateurs ne sont pas comme des listes. Ils ne stockent pas leurs résultats intermédiaires n'importe où, alors vous ne pouvez pas revenir en arrière. Je vais illustrer le problème avec un exemple simple en python repl:
Une fois que vous commencez à aller par le biais d'un générateur pour obtenir la n-ième valeur de la séquence, le générateur est maintenant dans un état différent, et en essayant d'obtenir le n-ième valeur de retourner un résultat différent, ce qui est susceptible d'entraîner un bug dans votre code.
Prenons un coup d'oeil à un autre exemple, basé sur le code de la question.
On pourrait d'abord attendre le suivant pour imprimer
4
deux fois.mais tapez ceci dans le repl et vous obtenez:
Bonne chance de traçage qui bug vers le bas.
EDIT:
Comme l'a souligné, si le générateur est infiniment longue, vous ne pouvez même pas la convertir en une liste. L'expression
list(gen)
ne finira jamais.Il ya une façon, vous pouvez mettre un paresseusement évalué la mise en cache wrapper autour d'une infinie générateur pour la faire ressembler à une liste infinie vous pourriez index en à volonté, mais qui mérite sa propre question et la réponse, et aurait de profondes implications sur les performances.
Les meilleurs à utiliser est :
exemple :
donc la réponse sera :
puis, quand vous voulez aller de l'indice spécifique, vous aurez à :
si vous voulez savoir uniquement le compte ou effectuer des opérations qui pas nécessaire de stocker en mémoire les meilleures pratiques seront :
a = sum(1 in i in a)
-> cela permettra de compter le nombre d'objets que vous avezespère que j'ai fait plus simple.
La première chose qui m'est venue à l'esprit était:
Peut-être vous devriez donner plus de détails sur un cas d'utilisation.
xrange(10)
à(i for i in xrange(10))
. S'avère que cette syntaxe fonctionne pourxrange
puisqu'il n'est pas vraiment un générateur de...xrange
antérieure générateurs, et renvoie un xrange objet, qui, de fait, met en œuvre la séquence complète du protocole de.vous pouvez simplement convertir le générateur dans une liste et d'utiliser l'index comme d'habitude: