क्या मैं पायथन में एक पुनरावर्तक/जेनरेटर रीसेट कर सकता हूं? मैं डिक्ट्रेडर का उपयोग कर रहा हूं और इसे फ़ाइल की शुरुआत में (सीएसवी मॉड्यूल से) रीसेट करना चाहता हूं।क्या इटरेटर को पायथन में रीसेट किया जा सकता है?
उत्तर
मैं itertools.tee सुझाव कई जवाब देखते हैं, लेकिन यह है कि इसके लिए डॉक्स में एक महत्वपूर्ण चेतावनी की अनदेखी कर रहा है:
यह itertool महत्वपूर्ण सहायक भंडारण की आवश्यकता हो सकती (कैसे पर निर्भर करता है अधिक अस्थायी डेटा संग्रहीत होने की आवश्यकता है)। आम तौर पर, यदि 0 इरेटर से पहले अधिकांश या सभी डेटा का उपयोग करता है, तो दूसरा इटरेटर शुरू होता है,
tee()
के बजायlist()
का उपयोग करने के लिए यह तेज़ है।
असल में, tee
उन स्थिति है जहाँ दो (या अधिक) एक इटरेटर के क्लोन है, जबकि एक दूसरे के साथ "सिंक से बाहर हो रही", इसलिए ज्यादा तक ऐसा नहीं करते के लिए डिज़ाइन किया गया है - बल्कि, वे वही "आसपास" (कुछ अन्य चीज़ों के पीछे या आगे) में कहें। "शुरुआत से फिर से शुरू करें" की ओपी की समस्या के लिए उपयुक्त नहीं है।
L = list(DictReader(...))
दूसरी तरफ पूरी तरह उपयुक्त है, जब तक कि डिक्ट्स की सूची स्मृति में आराम से फिट हो सके। iter(L)
के साथ किसी भी समय "बहुत हल्का और कम ओवरहेड) एक नया" इटेटरेटर "शुरू किया जा सकता है, और नए या मौजूदा लोगों को प्रभावित किए बिना पूरी तरह से या पूरी तरह से उपयोग किया जा सकता है; अन्य पहुंच पैटर्न भी आसानी से उपलब्ध हैं।
जैसा कि कई उत्तरों ने सही टिप्पणी की है, csv
के विशिष्ट मामले में आप .seek(0)
अंतर्निहित फ़ाइल ऑब्जेक्ट (बल्कि एक विशेष मामला) भी कर सकते हैं। मुझे यकीन नहीं है कि दस्तावेज और गारंटी है, हालांकि यह वर्तमान में काम करता है; यह शायद वास्तव में बड़ी सीएसवी फाइलों के लिए विचार करने योग्य होगा, जिसमें list
मैं अनुशंसा करता हूं क्योंकि सामान्य दृष्टिकोण में स्मृति पदचिह्न बहुत बड़ा होगा।
5 एमबी फ़ाइल पर एक csvreader पर मल्टीपासेज कैश करने के लिए 'सूची() 'का उपयोग करके मेरा रनटाइम ~ 12secs से ~ 0.5s तक जाता है। –
केवल अगर अंतर्निहित प्रकार ऐसा करने के लिए एक तंत्र प्रदान करता है (उदा। fp.seek(0)
)।
नहीं। पायथन का इटरेटर प्रोटोकॉल बहुत आसान है, और केवल एक एकल विधि (.next()
या __next__()
) प्रदान करता है, और सामान्य रूप से एक पुनरावर्तक को रीसेट करने की कोई विधि नहीं है।
सामान्य पैटर्न फिर से उसी प्रक्रिया का उपयोग करके एक नया इटरेटर बनाने के लिए है।
आप एक इटरेटर ताकि आप इसकी शुरुआत करने के लिए वापस जा सकते हैं "बंद बचाने" करना चाहते हैं, तो आप भी इटरेटर itertools.tee
जबकि आप .next() विधि का विश्लेषण कर रहे हैं शायद सही है, ओप क्या मांग रहा है पाने के लिए एक काफी सरल तरीका है। – Wilduck
@ विल्डक: मैं आपका जवाब देखता हूं। मैंने अभी पुनरावर्तक प्रश्न का उत्तर दिया, और मुझे 'सीएसवी' मॉड्यूल के बारे में कोई जानकारी नहीं है। उम्मीद है कि दोनों उत्तर मूल पोस्टर के लिए उपयोगी हैं। – u0b34a0f6ae
कड़ाई से, इटरेटर प्रोटोकॉल को भी '__iter__' की आवश्यकता होती है। यही है, इटेटर को भी पुनरावृत्तियों की आवश्यकता होती है। –
का उपयोग करके कांटा हो सकता है आप 'blah.csv' नामक एक 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)
के साथ एक DictReader बनाते हैं, आप के साथ अगली पंक्ति प्राप्त करने में सक्षम हो जाएगा 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}
फिर।
ऐसा लगता है कि आप जिस कार्यक्षमता की तलाश में हैं। मुझे यकीन है कि इस दृष्टिकोण से जुड़े कुछ चाल हैं कि मुझे हालांकि पता नहीं है। @ ब्रायन ने बस एक और डिक्ट्रेडर बनाने का सुझाव दिया। यदि आप पहली पाठक फ़ाइल को पढ़ने के माध्यम से आधे रास्ते हैं, तो यह काम नहीं करेगा, क्योंकि आपके नए पाठक के पास फ़ाइल में कहीं भी अप्रत्याशित कुंजी और मूल्य होंगे।
यह मेरे सिद्धांत ने मुझे बताया, यह देखने के लिए अच्छा लगा कि मैंने क्या सोचा था, करता है। –
@ विल्डक: डिक्ट्रेडर के दूसरे उदाहरण के साथ आप जो व्यवहार कर रहे हैं वह तब नहीं होगा जब आप एक नया फाइल हैंडल करते हैं और दूसरे डिक्ट्रेडर को पास करते हैं, है ना? – user248237dfsf
यदि आपके पास दो फ़ाइल हैंडलर हैं तो वे स्वतंत्र रूप से व्यवहार करेंगे, हां। – Wilduck
हालांकि कोई इटरेटर रीसेट नहीं है, पाइथन 2.6 (और बाद में) से "itertools" मॉड्यूल में कुछ उपयोगिताएं हैं जो वहां मदद कर सकती हैं। तब से एक "टीई" है जो एक इटरेटर की कई प्रतियां बना सकता है, और आगे चलने वाले परिणामों के कैश कर सकता है, ताकि इन परिणामों का उपयोग प्रतियों पर किया जा सके। मैं अपने उद्देश्यों के seve देगा:
>>> 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]
उपरोक्त एलेक्स मार्टेलि और वाइल्डक द्वारा वकालत के रूप में .seek (0) का उपयोग करने में एक बग है, अर्थात् .nxt() के लिए अगली कॉल आपको {key1: key1 के रूप में आपकी शीर्षलेख पंक्ति का एक शब्दकोश देगा , key2: key2, ...}। शीर्षलेख पंक्ति से छुटकारा पाने के लिए reader.next() को कॉल के साथ फ़ाइल.seek (0) का पालन करना है।
तो अपने कोड कुछ इस तरह दिखेगा:
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)
हाँ, यदि आप 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
'itertools.cycle' जैसे सरणी के माध्यम से' nditer' चक्र 'कर सकते हैं? – LWZ
@LWZ: मुझे ऐसा नहीं लगता है, लेकिन आप कोशिश कर सकते हैं: 'अगला()' और 'स्टॉपइटरेशन' अपवाद पर 'रीसेट() 'करें। –
... इसके बाद 'अगला() ' –
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()
यह शायद मूल प्रश्न के लिए ओर्थोगोनल है, लेकिन एक एक समारोह है कि इटरेटर रिटर्न में इटरेटर लपेट सकता है।
def get_iter():
return iterator
पुनरावर्तक को रीसेट करने के लिए बस फ़ंक्शन को फिर से कॉल करें। यह निश्चित रूप से मामूली है अगर समारोह में कहा गया फ़ंक्शन कोई तर्क नहीं लेता है।
यदि फ़ंक्शन को कुछ तर्कों की आवश्यकता होती है, तो funtools.partial का उपयोग मूल बंदरगाह के बजाय पास किए जाने वाले बंद करने के लिए करें।
def get_iter(arg1, arg2):
return iterator
from functools import partial
iter_clos = partial(get_iter, a1, a2)
यह और एक जनरेटर के लिए
list(generator())
रिटर्न सभी शेष मूल्यों क्या करने की जरूरत होगी कैशिंग कि टी (एन प्रतियां) या सूची (1 प्रतिलिपि) से बचने के लिए लगता है प्रभावी रूप से यह रीसेट करता है अगर यह फंस नहीं है ।
छोटी फ़ाइलों के लिए, आप more_itertools.seekable
का उपयोग करने पर विचार कर सकते हैं - एक तृतीय-पक्ष टूल जो iterables को रीसेट करने की पेशकश करता है।
डेमो
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'}
यहाँ एक DictReader
एक seekable
वस्तु में लपेटा जाता है (1) और उन्नत (2)। seek()
विधि को इटरेटर को 0 वें स्थान (3) पर रीसेट/रिवाइंड करने के लिए उपयोग किया जाता है।
नोट: स्मृति खपत पुनरावृत्ति के साथ बढ़ता है, इसलिए indicated in the docs के रूप में बड़ी फ़ाइलों को इस उपकरण को लागू करने से सावधान रहें।
समस्या
मेरे पास पहले भी यही समस्या है। मेरे कोड का विश्लेषण करने के बाद, मुझे एहसास हुआ कि लूप के अंदर इटरेटर को रीसेट करने का प्रयास थोड़ा जटिलता बढ़ाता है और यह कोड को थोड़ा बदसूरत बनाता है।
समाधान
ओपन फ़ाइल और स्मृति में एक चर के लिए पंक्तियों को बचाने के।
# 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)
अब आप पंक्तियों पुनरावर्तक के साथ काम कर के बिना अपने दायरे में कहीं भी के माध्यम से लूप कर सकते हैं।
[पाइथन में जेनरेटर ऑब्जेक्ट को रीसेट करना] के संभावित डुप्लिकेट (http://stackoverflow.com/questions/1271320/reseting-generator-object-in-python) – sschuberth