Može li se poništiti iteratori u Pythonu?

Mogu li poništiti iterator / generator u Pythonu? Koristim DictReader i želio bih ga resetirati (iz modula csv) na početak datoteke.

101
16 июля '10 в 18:00 2010-07-16 18:00 postavio user248237dfsf 16. srpnja '10. u 6:00 2010-07-16 18:00
@ 13 odgovora

Vidim mnogo odgovora koji nude itertools.tee , ali zanemarujući jedno važno upozorenje u dokumentima za njega:

Ova itertool može zahtijevati značajnu sekundarnu pohranu (ovisno o tome koliko su privremeni podaci pohranjeni). Općenito, ako jedan iterator koristi većinu ili sve podatke prije nego što se drugi iterator pokrene, brže će se koristiti list() umjesto tee() .

U principu, tee namijenjen onim situacijama gdje dva (ili više) klonova jednog iteratora, dok se "međusobno ne usklađuju", ne čine to mnogo - radije, govore u istom "susjedstvu" (nekoliko stavki iza ili jedna ispred druge). Nije prikladno za OP problem s "ponavljanjem od početka".

L = list(DictReader(...)) , s druge strane, odličan je ako se popis diktona može jednostavno smjestiti u memoriju. Novi "iterator od početka" (vrlo lagan i nizak opterećenje) može se izvesti u bilo koje vrijeme s iter(L) i koristiti djelomično ili potpuno bez utjecaja na nove ili postojeće; Dostupni su i drugi načini pristupa.

Kao što je nekoliko odgovora pošteno zabilježeno, u specifičnom slučaju csv možete također .seek(0) osnovni objekt datoteke (sasvim poseban slučaj). Nisam siguran da je dokumentiran i zajamčen, iako trenutno radi; To je vjerojatno vrijedno razmatranja samo za stvarno velike CSV datoteke, u kojima preporučujem list , budući da će opći pristup imati previše memorije.

67
16 июля '10 в 19:39 2010-07-16 19:39 Odgovor je dao Alex Martelli 16. srpnja '10. u 19:39. 2010-07-16 19:39

Ako imate csv datoteku pod nazivom 'blah.csv' izgleda kao

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

znate da možete otvoriti datoteku za čitanje i kreirati DictReader

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

Zatim možete dobiti sljedeći redak s reader.next() , koji bi trebao izlaziti

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

koristeći ga opet, dobit ćete

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

Međutim, u ovom trenutku, ako koristite blah.seek(0) , sljedeći put reader.next() nazovete reader.next() dobit ćete

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

ponovo.

Čini se da je ovo funkcija koju tražite. Siguran sam da postoje neki trikovi koji se odnose na ovaj pristup i za koje ne znam. @ Brian je predložio jednostavno stvaranje još jednog DictReadera. To neće raditi ako ste prvi čitatelj koji je na pola puta čitao datoteku jer će vaš novi čitač imati neočekivane ključeve i vrijednosti od mjesta na kojem se nalazite u datoteci.

29
16 июля '10 в 18:24 2010-07-16 18:24 odgovor je dat Wilduck 16. srpnja '10 u 18:24 2010-07-16 18:24

Ne. Python iterator protokol je vrlo jednostavan i pruža samo jednu metodu ( .next() ili __next__() ), a ne metodu za resetiranje iteratora uopće.

Generički predložak - umjesto toga ponovno izradite novi iterator pomoću istog postupka.

Ako želite spremiti iterator tako da se možete vratiti na njegov početak, također možete ponoviti iterator pomoću itertools.tee

21
16 июля '10 в 18:18 2010-07-16 18:18 odgovor je dat u0b34a0f6ae 16. srpnja '10. u 18:18 2010-07-16 18:18

Da , ako koristite numpy.nditer za izradu iteratora.

 >>> lst = [1,2,3,4,5] >>> itr = numpy.nditer([lst]) >>> itr.next() 1 >>> itr.next() 2 >>> itr.finished False >>> itr.reset() >>> itr.next() 1 
10
30 дек. Odgovor je dan Developer 30 Dec. 2012-12-30 13:06 '12 u 13:06 2012-12-30 13:06

Došlo je do pogreške u korištenju .seek (0), kao što su predložili Alex Martelli i Wilduk gore, a to je da će vam sljedeći .next () poziv dati rječnik vašeg retka zaglavlja u obliku {key1: key1, key2: key2, .. .}. Zaobilazno rješenje je slijediti file.seek (0) s reader.next () da biste se riješili retka zaglavlja.

Vaš će kôd izgledati ovako:

 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) 
10
16 июля '10 в 20:56 2010-07-16 20:56 Odgovor je dao Steven Rumbalski 16. srpnja '10. U 20:56. 2010-07-16 20:56

Iako nema iteratora za resetiranje, itertools modul iz pythona 2.6 (i kasnije) ima neke pomoćne programe koji tamo mogu pomoći. Jedan od njih je model koji može stvoriti višestruke iteratorske kopije i predmemorirati rezultate onoga što se izvršava kako bi se ti rezultati koristili na kopijama. Ja ću slijediti vaše ciljeve:

 >>> def printiter(n): ... for i in xrange(n): ... print "iterating value %d" % i ... yield i >>> from itertools import tee >>> a, b = tee(printiter(5), 2) >>> list(a) iterating value 0 iterating value 1 iterating value 2 iterating value 3 iterating value 4 [0, 1, 2, 3, 4] >>> list(b) [0, 1, 2, 3, 4] 
2
16 июля '10 в 19:22 2010-07-16 19:22 odgovor je dao jsbueno 16. srpnja '10 u 19:22 2010-07-16 19:22

To je možda ortogonalno izvornom pitanju, ali iterator možete zamotati u funkciju koja vraća iterator.

 def get_iter(): return iterator 

U resetiranju, iterator ponovno poziva funkciju. To je, naravno, trivijalno ako je funkcija kad specificirana funkcija ne uzima argumente.

U slučaju kada funkcija zahtijeva neke argumente, koristite functools.partial za stvaranje zatvaranja koje se može prenijeti umjesto izvornog iteratora.

 def get_iter(arg1, arg2): return iterator from functools import partial iter_clos = partial(get_iter, a1, a2) 

Čini se da to ne dopušta predmemoriranje koje će se morati izvršiti čarobnjakom (n kopija) ili popisom (1 instanca)

2
19 февр. odgovor od Anish Feb 19 2015-02-19 02:37 '15 u 2:37 2015-02-19 02:37

Problem je

Imao sam isti problem. Nakon analize moje šifre, shvatio sam da pokušaj resetiranja iteratora unutar petlji malo povećava vremensku složenost, a isto tako čini kod je malo ružan.

odluka

Otvorite datoteku i spremite retke u varijable u memoriji.

 # initialize list of rows rows = [] # open the file and temporarily name it as 'my_file' with open('myfile.csv', 'rb') as my_file: # set up the reader using the opened file myfilereader = csv.DictReader(my_file) # loop through each row of the reader for row in myfilereader: # add the row to the list of rows rows.append(row) 

Sada možete kružiti kroz redove bilo gdje u vašem području bez upućivanja na iterator.

1
31 янв. Odgovor je dao Anthony Holloman 31. siječnja. 2018-01-31 22:18 '18 u 22:18 sati 2018-01-31 22:18

Za male datoteke možete koristiti more_itertools.seekable , alat treće strane koji nudi poništavanje iteracija.

demo

 import csv import more_itertools as mit filename = "data/iris.csv" with open(filename, "r") as f: reader = csv.DictReader(f) iterable = mit.seekable(reader) # 1 print(next(iterable)) # 2 print(next(iterable)) print(next(iterable)) print("\nReset iterable\n--------------") iterable.seek(0) # 3 print(next(iterable)) print(next(iterable)) print(next(iterable)) 

izlaz

 {'Sepal width': '3.5', 'Petal width': '0.2', 'Petal length': '1.4', 'Sepal length': '5.1', 'Species': 'Iris-setosa'} {'Sepal width': '3', 'Petal width': '0.2', 'Petal length': '1.4', 'Sepal length': '4.9', 'Species': 'Iris-setosa'} {'Sepal width': '3.2', 'Petal width': '0.2', 'Petal length': '1.3', 'Sepal length': '4.7', 'Species': 'Iris-setosa'} Reset iterable -------------- {'Sepal width': '3.5', 'Petal width': '0.2', 'Petal length': '1.4', 'Sepal length': '5.1', 'Species': 'Iris-setosa'} {'Sepal width': '3', 'Petal width': '0.2', 'Petal length': '1.4', 'Sepal length': '4.9', 'Species': 'Iris-setosa'} {'Sepal width': '3.2', 'Petal width': '0.2', 'Petal length': '1.3', 'Sepal length': '4.7', 'Species': 'Iris-setosa'} 

Ovdje je DictReader zatvoren u seekable objektu (1) i proširen (2). Metoda seek() se koristi za resetiranje / premotavanje iteratora na 0-tu poziciju (3).

Napomena: potrošnja memorije raste s iteracijom, stoga budite oprezni s korištenjem ovog alata za velike datoteke, kako je navedeno u dokumentima .

1

Samo ako osnovni tip pruža mehanizam za to (na primjer, fp.seek(0) ).

0
16 июля '10 в 18:04 2010-07-16 18:04 Odgovor daje Ignacio Vazquez-Abrams 16. srpnja '10. U 18:04. 2010-07-16 18:04

Za DictReader:

 f = open(filename, "rb") d = csv.DictReader(f, delimiter=",") f.seek(0) d.__init__(f, delimiter=",") 

Za DictWriter:

 f = open(filename, "rb+") d = csv.DictWriter(f, fieldnames=fields, delimiter=",") f.seek(0) f.truncate(0) d.__init__(f, fieldnames=fields, delimiter=",") d.writeheader() f.flush() 
0
19 сент. Odgovor je dan mAsT3RpEE 19. rujna. 2013-09-19 17:17 '13 u 17:17 2013-09-19 17:17

Moguća opcija je da koristite itertools.cycle () , koja vam omogućuje da se beskrajno ponavljate bez ikakvih trikova kao što je .seek (0).

 iterDic = itertools.cycle(csv.DictReader(open('file.csv'))) 
0
12 янв. Odgovor Greg H 12. siječnja 2019-01-12 12:26 '19 u 12:26 sati 2019-01-12 12:26

Ostala pitanja o oznakama ili Postavi pitanje