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.
Réponses
Trop de publicités?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 detee()
.
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.
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.
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
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)