159 votes

Les itérateurs peuvent-ils être réinitialisés en Python?

Puis-je réinitialiser un itérateur / générateur en Python? J'utilise DictReader et souhaite le réinitialiser (à partir du module CSV) au début du fichier.

96voto

Alex Martelli Points 330805

Je vois beaucoup de réponses suggérant itertools.té, mais c'est ignorer crucial d'avertissement dans les docs pour elle:

Cette itertool peut nécessiter beaucoup de auxiliaire de stockage (en fonction de la façon dont beaucoup de données temporaire doit être stockées). En général, si un itérateur utilise la plupart ou toutes les données avant de les un autre itérateur commence, il est plus rapide pour utiliser list() au lieu de tee().

Fondamentalement, tee est conçu pour les situations où deux (ou plus) des clones d'un itérateur, tandis que "sortir de la synchronisation" les uns avec les autres, de ne pas le faire par beaucoup , assez, disent-ils dans le même "proximité" (quelques articles en retard ou en avance les uns des autres). Ne convient pas pour les OP du problème de "refaire depuis le début".

L = list(DictReader(...)) sur l'autre main est parfaitement adapté, aussi longtemps que la liste des dicts peut épouser la forme de la mémoire. Un nouveau "itérateur de début" (très léger et faible charge) peut être effectué à tout moment avec iter(L), et utilisés en partie ou en totalité, sans affecter de nouvelles ou existantes; d'autres modèles d'accès sont également facilement accessibles.

Comme plusieurs réponses, à juste titre, fait remarquer, dans le cas spécifique de l' csv vous pouvez également .seek(0) le fichier sous-jacent de l'objet (un cas assez particulier). Je ne suis pas sûr que ce soit documenté et de la garantie, si elle ne travaille actuellement; il serait sans doute utile d'envisager seulement pour vraiment énormes fichiers csv, dans lequel l' list - je recommander que la démarche générale aurait une trop grande quantité de mémoire.

37voto

Wilduck Points 5116

Si vous avez un fichier csv nommé 'bla.csv " Qui ressemble à

a,b,c,d
1,2,3,4
2,3,4,5
3,4,5,6

vous savez que vous pouvez ouvrir le fichier pour le lire, et de créer un DictReader avec

blah = open('blah.csv', 'r')
reader= csv.DictReader(blah)

Ensuite, vous serez en mesure d'obtenir la ligne suivante avec reader.next(), ce qui devrait sortie

{'a':1,'b':2,'c':3,'d':4}

de l'utiliser à nouveau produira

{'a':2,'b':3,'c':4,'d':5}

Toutefois, à ce stade, si vous utilisez blah.seek(0),, la prochaine fois que vous appelez reader.next() , vous obtiendrez

{'a':1,'b':2,'c':3,'d':4}

de nouveau.

Cela semble être la fonctionnalité que vous recherchez. Je suis sûr qu'il ya quelques trucs liés à cette approche que je ne suis pas au courant. @Brian a suggéré de créer simplement un autre DictReader. Cela ne fonctionnera pas si vous êtes le premier lecteur est à mi-chemin par le biais de la lecture du fichier, comme votre nouveau lecteur d'avoir des clés et des valeurs de n'importe où dans le fichier.

28voto

u0b34a0f6ae Points 14874

Le protocole d'itérateur de Python est très simple et ne fournit qu'une seule méthode ( .next() ou __next__() ), et aucune méthode pour réinitialiser un itérateur en général.

Le modèle courant consiste à créer un nouvel itérateur à la place.

Si vous voulez "sauver" un itérateur afin de pouvoir en revenir au début, vous pouvez également créer un itérateur à l'aide de itertools.tee

11voto

Steven Rumbalski Points 16838

Il y a un bogue dans l'utilisation de .seek (0) comme le préconisent Alex Martelli et Wilduck ci-dessus, à savoir que le prochain appel à .next () vous donnera un dictionnaire de votre rangée d'en-tête sous la forme {key1: key1, key2: key2 , ...}. La solution consiste à suivre file.seek (0) avec un appel à reader.next () pour supprimer la ligne d’en-tête.

Donc, votre code ressemblerait à quelque chose comme ça:

 f_in = open('myfile.csv','r')
reader = csv.DictReader(f_in)

for record in reader:
    if some_condition:
        # reset reader to first row of data on 2nd line of file
        f_in.seek(0)
        reader.next()
        continue
    do_something(record)
 

11voto

Developer Points 1944

Oui , si vous utilisez numpy.nditer pour construire votre itérateur.

 >>> lst = [1,2,3,4,5]
>>> itr = numpy.nditer([lst])
>>> itr.next()
1
>>> itr.next()
2
>>> itr.finished
False
>>> itr.reset()
>>> itr.next()
1
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X