Ar „iteratoriai“ gali būti iš naujo nustatyti „Python“?

Ar galiu iš naujo nustatyti iteratorių / generatorių „Python“? Aš naudoju „DictReader“ ir norėčiau ją iš naujo nustatyti (nuo csv modulio) iki failo pradžios.

101
16 июля '10 в 18:00 2010-07-16 18:00 nustatė user248237dfsf liepos 16 d., 10 val., 6:00, 2010-07-16 18:00
@ 13 atsakymų

Aš matau daug atsakymų, siūlančių itertools.tee , bet ignoruojant vieną svarbų įspėjimą dokumentuose:

Tai gali reikėti didelės antrinės atminties (priklausomai nuo laikinų duomenų kiekio). Apskritai, jei vienas iteratorius naudoja daugumą ar visus duomenis prieš pradedant kitą iteratorių, list() naudojimas greičiau yra vietoj tee() .

Iš esmės tai tee skirta toms situacijoms, kai du (ar daugiau) vieno iteratoriaus klonai, nors „išeina iš sinchronizavimo“ tarpusavyje, to nedaro, o jie kalba toje pačioje „kaimynystėje“ (keli elementai atsilieka arba vienas prieš kitą). Netinka OP problemai su „pasikartojimu nuo pradžios“.

Kita vertus, L = list(DictReader(...)) yra puikus, jei diktonų sąrašas gali patogiai įsilieti į atmintį. Naujas „iteratorius nuo pradžios“ (labai lengvas ir mažas viršutinis) gali būti atliekamas bet kuriuo metu su iter(L) ir naudojamas iš dalies arba visiškai, nedarant įtakos naujiems ar esamiems; kitos prieigos sistemos taip pat yra lengvai prieinamos.

Kaip teisingai pažymėjo keletas atsakymų, konkrečiu atveju - csv taip pat galite .seek(0) pagrindinį failo objektą (gana ypatingą atvejį). Nesu tikras, kad jis yra dokumentuotas ir garantuotas, nors šiuo metu jis veikia; Tai tikriausiai verta apsvarstyti tik tikrai didelius csv failus, kuriuose rekomenduoju list , nes bendras požiūris turės per daug atminties.

67
16 июля '10 в 19:39 2010-07-16 19:39 atsakymą pateikė Alex Martelli liepos 10 d., 19:39, 2010-07-16 19:39

Jei turite csv failą pavadinimu 'blah.csv' Atrodo

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

žinote, kad galite atidaryti failą skaitymui ir sukurti „DictReader“ su

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

Tada galite gauti kitą eilutę su reader.next() , kuris turėtų reader.next()

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

vėl jį naudosite

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

Tačiau šiuo metu, jei naudojate blah.seek(0) , kitą kartą, reader.next() skambinsite reader.next() , gausite

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

dar kartą.

Atrodo, kad tai yra funkcionalumas, kurio ieškote. Esu tikras, kad yra keletas triukų, susijusių su šiuo požiūriu, apie kurį aš nežinau. @Brian pasiūlė tiesiog sukurti kitą „DictReader“. Tai neveiks, jei esate pirmasis skaitytojas pusiau per skaitydami failą, nes jūsų naujasis skaitytojas turės netikėtų raktų ir vertybių iš vietos, kurioje esate faile.

29
16 июля '10 в 18:24 2010-07-16 18:24 atsakymas pateikiamas Wilduck liepos 16 d., 18:24, 2010-07-16 18:24

Ne „Python“ iteratoriaus protokolas yra labai paprastas ir pateikia tik vieną metodą ( .next() arba __next__() ), o ne metodą, kaip iš naujo nustatyti iteratorių.

Bendras šablonas - vietoj to dar kartą sukurkite naują iteratorių.

Jei norite išsaugoti iteratorių, kad galėtumėte grįžti į pradžią, taip pat galite kartoti iteratorių naudodami itertools.tee

21
16 июля '10 в 18:18 2010-07-16 18:18 atsakymas pateikiamas u0b34a0f6ae liepos 16, 10, 18:18, 2010-07-16 18:18

Taip , jei naudojate numpy.nditer kad sukurtumėte iteratorių.

 >>> 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 дек. Atsakymas pateikiamas Kūrėjas 30 Dec. 2012-12-30 13:06 '12, 13:06, 2012-12-30 13:06

Naudojant .seek (0) klaidą, kaip pasiūlė Alex Martelli ir Wilduk aukščiau, būtent, kad kitas .next () skambutis suteiks jums antraštės eilutės žodyną formoje {key1: key1, key2: key2, .. .}. Problema yra sekti file.seek (0) su skaitytuvu.next (), kad atsikratytumėte antraštės eilutės.

Taigi, jūsų kodas bus toks:

 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 Atsakymą pateikė Steven Rumbalski , liepos 16 d. 10 val. 20:56 2010-07-16 20:56

Nors nėra iš naujo nustatyto iteratoriaus, „2.6“ (ir vėlesnės versijos) „itertools“ modulyje yra keletas paslaugų, kurios gali padėti. Vienas iš jų yra tee, kuri gali sukurti kelias iteratorines kopijas, ir talpina rezultatus, kurie yra vykdomi, kad šie rezultatai būtų naudojami kopijose. Aš sieksiu jūsų tikslų:

 >>> 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 atsakymą pateikė jsbueno, liepos 16 d., 10 val., 19:22, 2010-07-16 19:22

Tai galbūt stačiakampis su pradiniu klausimu, tačiau jūs galite įvesti iteratorių į funkciją, kuri grąžina iteratorių.

 def get_iter(): return iterator 

Atstatymo metu iteratorius dar kartą skambina. Tai, žinoma, yra nereikšminga, jei funkcija, kai nurodyta funkcija nesiima jokių argumentų.

Tuo atveju, kai funkcijai reikia tam tikrų argumentų, naudokite functools.partial, kad sukurtumėte uždarą vietą, kuri gali būti perduota vietoj pirminio iteratoriaus.

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

Atrodo, kad tai neleidžia talpykloje laikyti, kad reikės atlikti (kopijas) arba sąrašą (1 egzempliorius)

2
19 февр. Atsakymą pateikė Anishas vasario 19 d. 2015-02-19 02:37 '15 at 2:37 2015-02-19 02:37

Problema

Turėjau tą pačią problemą. Išnagrinėjęs mano kodą, supratau, kad bandymas iš naujo nustatyti iteratoriaus viduje esančias kilpas šiek tiek padidina laiko sudėtingumą, o kodą - šiek tiek negraži.

Sprendimas

Atidarykite failą ir išsaugokite atmintyje esančius kintamuosius.

 # 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) 

Dabar galite pereiti per eilutes bet kurioje jūsų vietovėje, nepaminėdami iteratoriaus.

1
31 янв. Atsakymą pateikė Anthony Holloman, sausio 31 d 2018-01-31 22:18 '18, 10:18 val. 2018-01-31 22:18

Jei naudojate mažus failus, galite naudoti more_itertools.seekable , trečiosios šalies įrankį, kuris siūlo iš naujo nustatyti iteracijas.

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)) 

Išeiti

 {'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'} 

Čia DictReader pridedamas prie objekto, kurio galima seekable (1) ir išplėstas (2). Taikymo seek() metodas naudojamas iteratoriaus atstatymui / perbraukimui į 0 poziciją (3).

Pastaba: atminties suvartojimas didėja su iteracija, todėl būkite atsargūs naudodami šį įrankį dideliems failams, kaip nurodyta dokumentuose .

1
05 дек. Atsakymas duotas 05 gruodžio. 2017-12-05 05:34 '17 at 5:34 am 2017-12-05 05:34

list(generator()) grąžina visas likusias generatoriaus vertes ir efektyviai atstato jį, jei jis nėra sujungtas.

0
20 мая '15 в 9:27 2015-05-20 09:27 Theoremiser atsakymas gegužės 20 d., 15 val. 9:27 2015-05-20 09:27

Tik tuo atveju, jei pagrindo tipas suteikia tai mechanizmui (pvz., fp.seek(0) ).

0
16 июля '10 в 18:04 2010-07-16 18:04 Atsakymą davė Ignacio Vazquez-Abrams liepos 16, 10 d. 18:04 2010-07-16 18: 04

DictReader:

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

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 сент. Atsakymas pateikiamas mAsT3RpEE 19 rugsėjis. 2013-09-19 17:17 '13, 17:17, 2013-09-19 17:17

Galimas variantas yra naudoti itertools.cycle () , kuris leidžia jums be galo kartoti be jokių triukų, pvz., .Seek (0).

 iterDic = itertools.cycle(csv.DictReader(open('file.csv'))) 
0
12 янв. Greg H 12 atsakymas 2019-01-12 12:26 '19 , 12:26 pm 2019-01-12 12:26

Kiti klausimai apie žymes arba Užduoti klausimą