क्या मैं पायथन में एक इट्रेटर / जनरेटर रीसेट कर सकता हूं? मैं DictReader का उपयोग कर रहा हूं और इसे फ़ाइल की शुरुआत में रीसेट करना चाहूंगा।
क्या मैं पायथन में एक इट्रेटर / जनरेटर रीसेट कर सकता हूं? मैं DictReader का उपयोग कर रहा हूं और इसे फ़ाइल की शुरुआत में रीसेट करना चाहूंगा।
जवाबों:
मैं कई उत्तरों को पुनरावृति का सुझाव देता देख रहा हूं , लेकिन इसके लिए डॉक्स में एक महत्वपूर्ण चेतावनी की अनदेखी कर रहा है:
इस इटर्टूल को महत्वपूर्ण सहायक भंडारण की आवश्यकता हो सकती है (यह निर्भर करता है कि कितने अस्थायी डेटा को संग्रहीत करने की आवश्यकता है)। सामान्य तौर पर, यदि एक पुनरावृत्तिकर्ता किसी अन्य पुनरावृत्ति शुरू होने से पहले डेटा का सबसे या सभी का उपयोग करता है, तो
list()
इसके बजाय इसका उपयोग करना तेज़ होता हैtee()
।
असल में, tee
उन स्थिति है जहाँ दो (या अधिक) एक इटरेटर के क्लोन है, जबकि एक दूसरे के साथ "सिंक से बाहर हो रही", ऐसा नहीं करते हैं के लिए डिज़ाइन किया गया है ज्यादा से बल्कि, वे एक ही "आसपास के क्षेत्र" में कहते हैं कि (क - कुछ वस्तुओं के पीछे या एक दूसरे से आगे)। "शुरू से फिर से करें" ओपी की समस्या के लिए उपयुक्त नहीं है।
L = list(DictReader(...))
दूसरी ओर पूरी तरह से उपयुक्त है, जब तक कि डीकट्स की सूची स्मृति में आराम से फिट हो सकती है। एक नया "प्रारंभकर्ता से शुरू" (बहुत हल्का और कम-ओवरहेड) किसी भी समय बनाया जा सकता है iter(L)
, और नए या मौजूदा वाले को प्रभावित किए बिना भाग या पूरे में उपयोग किया जा सकता है; अन्य पहुंच पैटर्न भी आसानी से उपलब्ध हैं।
कई जवाब ठीक ही टिप्पणी की है, के विशिष्ट मामले में csv
आप कर सकते हैं भी .seek(0)
अंतर्निहित फ़ाइल वस्तु (एक नहीं बल्कि विशेष मामला)। मुझे यकीन नहीं है कि यह दस्तावेज और गारंटी है, हालांकि यह वर्तमान में काम करता है; यह शायद केवल वास्तव में विशाल सीएसवी फ़ाइलों के लिए विचार करने के लायक होगा, जिसमें list
मैं सामान्य दृष्टिकोण के रूप में सिफारिश करता हूं बहुत बड़ी मेमोरी मेमोरी होगी।
list()
एमबी फ़ाइल पर सीएसवीडर पर कैश मल्टीपज का उपयोग करने से मेरा रनटाइम ~ 12secs से ~ 0.5 s तक चला जाता है।
अगर आपके पास 'blah.csv' नाम की एक सीएसवी फाइल है, जो कि दिखती है
a,b,c,d
1,2,3,4
2,3,4,5
3,4,5,6
आप जानते हैं कि आप पढ़ने के लिए फ़ाइल खोल सकते हैं, और एक डिक्टरेडर बना सकते हैं
blah = open('blah.csv', 'r')
reader= csv.DictReader(blah)
फिर, आप अगली पंक्ति को प्राप्त करने में सक्षम होंगे reader.next()
, जिसे आउटपुट करना चाहिए
{'a':1,'b':2,'c':3,'d':4}
इसका दोबारा उपयोग करने से उत्पादन होगा
{'a':2,'b':3,'c':4,'d':5}
हालांकि, इस बिंदु पर यदि आप उपयोग करते हैं blah.seek(0)
, तो अगली बार जब आप कॉल reader.next()
करेंगे तो आपको मिलेगा
{'a':1,'b':2,'c':3,'d':4}
फिर।
ऐसा लगता है कि आप जिस कार्यशीलता की तलाश कर रहे हैं। मुझे यकीन है कि इस दृष्टिकोण से जुड़े कुछ ट्रिक्स हैं जो मुझे इसके बारे में पता नहीं हैं। @ ब्रायन ने बस एक और DictReader बनाने का सुझाव दिया। यह काम नहीं करेगा यदि आप पहले पाठक फ़ाइल को पढ़ने के माध्यम से आधे रास्ते में हैं, क्योंकि आपके नए पाठक के पास फ़ाइल में आप जहाँ भी हैं वहां से अप्रत्याशित कुंजी और मान होंगे।
नहीं। पायथन का इटरेटर प्रोटोकॉल बहुत सरल है, और केवल एक एकल विधि ( .next()
या __next__()
) प्रदान करता है , और सामान्य रूप से एक इटेरेटर को रीसेट करने की कोई विधि नहीं है।
सामान्य पैटर्न के बजाय फिर से एक ही प्रक्रिया का उपयोग करके एक नया पुनरावृत्ति बनाना है।
यदि आप एक पुनरावृत्ति को "सेव" करना चाहते हैं ताकि आप इसकी शुरुआत में वापस जा सकें, तो आप उपयोग करके इट्रियर्स को भी निकाल सकते हैं itertools.tee
csv
मॉड्यूल के बारे में कोई पता नहीं है । उम्मीद है कि दोनों उत्तर मूल पोस्टर के लिए उपयोगी हैं।
__iter__
। यानी पुनरावृत्तियों के लिए पुनरावृत्तियों की भी आवश्यकता होती है।
हां , यदि आप numpy.nditer
अपने पुनरावृति का निर्माण करने के लिए उपयोग करते हैं।
>>> lst = [1,2,3,4,5]
>>> itr = numpy.nditer([lst])
>>> itr.next()
1
>>> itr.next()
2
>>> itr.finished
False
>>> itr.reset()
>>> itr.next()
1
nditer
जैसे सरणी के माध्यम से चक्र कर सकते हैं itertools.cycle
?
try:
next()
StopIteration
reset()
next()
.seek(0)
ऊपर एलेक्स मार्टेली और वाइल्डक द्वारा वकालत के रूप में उपयोग करने के लिए एक बग है , अर्थात् अगली कॉल .next()
आपको अपनी हेडर पंक्ति के रूप में एक शब्दकोश देगी {key1:key1, key2:key2, ...}
। हेडर पंक्ति से छुटकारा पाने के लिए file.seek(0)
कॉल के साथ काम करना है reader.next()
।
तो आपका कोड कुछ इस तरह दिखाई देगा:
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)
यह शायद मूल प्रश्न के लिए रूढ़िवादी है, लेकिन एक पुनरावृत्ति करने वाले फ़ंक्शन में पुनरावृत्ति को लपेट सकता है।
def get_iter():
return iterator
पुनरावृत्ति रीसेट करने के लिए बस फ़ंक्शन को फिर से कॉल करें। यह निश्चित रूप से तुच्छ है यदि फ़ंक्शन जब उक्त फ़ंक्शन कोई तर्क नहीं लेता है।
इस मामले में कि फ़ंक्शन को कुछ तर्कों की आवश्यकता होती है, मूल बंद करने वाले के बजाय पारित होने के लिए एक क्लोजर बनाने के लिए फंक्शनल टूल का उपयोग करें।
def get_iter(arg1, arg2):
return iterator
from functools import partial
iter_clos = partial(get_iter, a1, a2)
ऐसा लगता है कि कै से बचने के लिए टी (एन प्रतियां) या सूची (1 प्रति) की आवश्यकता होगी
छोटी फ़ाइलों के लिए, आप उपयोग करने पर विचार कर सकते हैं more_itertools.seekable
- एक तृतीय-पक्ष उपकरण जो पुनरावृत्तियाँ प्रदान करता है।
डेमो
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))
उत्पादन
{'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'}
यहाँ एक वस्तु (1) और उन्नत (2) DictReader
में लिपटा हुआ है seekable
। seek()
विधि रीसेट / 0 स्थिति (3) को इटरेटर रिवाइंड करने के लिए प्रयोग किया जाता है।
नोट: मेमोरी खपत पुनरावृत्ति के साथ बढ़ती है, इसलिए इस उपकरण को बड़ी फ़ाइलों पर लागू करने से सावधान रहें, जैसा कि डॉक्स में दर्शाया गया है ।
हालांकि कोई पुनरावृत्ति रीसेट नहीं है, अजगर 2.6 से (और बाद में) "इटर्टूलस" मॉड्यूल में कुछ उपयोगिताओं हैं जो वहां मदद कर सकते हैं। एक तो "टी" है जो एक पुनरावृत्त की कई प्रतियां बना सकता है, और आगे चल रहे परिणामों को कैश कर सकता है, ताकि इन परिणामों का उपयोग कॉपियों पर किया जाए। मैं आपके उद्देश्यों को पूरा करूंगा:
>>> 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]
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()
list(generator())
एक जनरेटर के लिए सभी शेष मान लौटाता है और प्रभावी रूप से रीसेट करता है यदि यह लूप नहीं है।
मैंने पहले भी यही मुद्दा उठाया है। अपने कोड का विश्लेषण करने के बाद, मैंने महसूस किया कि लूप के अंदर पुनरावृत्ति को रीसेट करने का प्रयास समय की जटिलता को थोड़ा बढ़ाता है और यह कोड को थोड़ा बदसूरत बना देता है।
फ़ाइल खोलें और मेमोरी में पंक्तियों को एक चर में सहेजें।
# 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)
अब आप एक पुनरावृत्ति से निपटने के बिना अपने दायरे में कहीं भी पंक्तियों के माध्यम से लूप कर सकते हैं ।
एक संभव विकल्प का उपयोग करना है itertools.cycle()
, जो आपको बिना किसी चाल के अनिश्चित काल तक पुनरावृति करने की अनुमति देगा .seek(0)
।
iterDic = itertools.cycle(csv.DictReader(open('file.csv')))
मैं इसी मुद्दे पर आ रहा हूं - जब मैं tee()
समाधान पसंद करता हूं, तो मुझे नहीं पता कि मेरी फाइलें कितनी बड़ी होने जा रही हैं और स्मृति पहले एक का उपभोग करने के बारे में चेतावनी दे रही हैं, जबकि दूसरे मुझे उस पद्धति को अपनाने से रोक रहे हैं।
इसके बजाय, मैं iter()
बयानों का उपयोग करके और अपने शुरुआती रन-थ्रू के लिए पहले का उपयोग करके पुनरावृत्तियों की एक जोड़ी बना रहा हूं , अंतिम रन के लिए दूसरे पर स्विच करने से पहले।
तो, एक तानाशाह पाठक के मामले में, अगर पाठक का उपयोग कर परिभाषित किया गया है:
d = csv.DictReader(f, delimiter=",")
मैं इस "विनिर्देश" से पुनरावृत्तियों की एक जोड़ी बना सकता हूं - उपयोग करना:
d1, d2 = iter(d), iter(d)
मैं तब अपना प्रथम-पास कोड चला सकता हूं d1
, इस ज्ञान में सुरक्षित कि दूसरा पुनरावृत्त d2
उसी मूल विनिर्देश से परिभाषित किया गया है।
मैंने यह पूरी तरह से परीक्षण नहीं किया है, लेकिन यह डमी डेटा के साथ काम करता है।
केवल अगर अंतर्निहित प्रकार ऐसा करने के लिए एक तंत्र प्रदान करता है (जैसे fp.seek(0)
)।
'पुनरावृति ()' कॉल के दौरान अंतिम पुनरावृत्ति पर एक नया बनाया पुनरावृत्ति लौटाएँ
class ResetIter:
def __init__(self, num):
self.num = num
self.i = -1
def __iter__(self):
if self.i == self.num-1: # here, return the new object
return self.__class__(self.num)
return self
def __next__(self):
if self.i == self.num-1:
raise StopIteration
if self.i <= self.num-1:
self.i += 1
return self.i
reset_iter = ResetRange(10)
for i in reset_iter:
print(i, end=' ')
print()
for i in reset_iter:
print(i, end=' ')
print()
for i in reset_iter:
print(i, end=' ')
आउटपुट:
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9