2010-07-16 7 views
89

क्या मैं पायथन में एक पुनरावर्तक/जेनरेटर रीसेट कर सकता हूं? मैं डिक्ट्रेडर का उपयोग कर रहा हूं और इसे फ़ाइल की शुरुआत में (सीएसवी मॉड्यूल से) रीसेट करना चाहता हूं।क्या इटरेटर को पायथन में रीसेट किया जा सकता है?

+0

[पाइथन में जेनरेटर ऑब्जेक्ट को रीसेट करना] के संभावित डुप्लिकेट (http://stackoverflow.com/questions/1271320/reseting-generator-object-in-python) – sschuberth

उत्तर

59

मैं itertools.tee सुझाव कई जवाब देखते हैं, लेकिन यह है कि इसके लिए डॉक्स में एक महत्वपूर्ण चेतावनी की अनदेखी कर रहा है:

यह itertool महत्वपूर्ण सहायक भंडारण की आवश्यकता हो सकती (कैसे पर निर्भर करता है अधिक अस्थायी डेटा संग्रहीत होने की आवश्यकता है)। आम तौर पर, यदि 0 इरेटर से पहले अधिकांश या सभी डेटा का उपयोग करता है, तो दूसरा इटरेटर शुरू होता है, tee() के बजाय list() का उपयोग करने के लिए यह तेज़ है।

असल में, tee उन स्थिति है जहाँ दो (या अधिक) एक इटरेटर के क्लोन है, जबकि एक दूसरे के साथ "सिंक से बाहर हो रही", इसलिए ज्यादा तक ऐसा नहीं करते के लिए डिज़ाइन किया गया है - बल्कि, वे वही "आसपास" (कुछ अन्य चीज़ों के पीछे या आगे) में कहें। "शुरुआत से फिर से शुरू करें" की ओपी की समस्या के लिए उपयुक्त नहीं है।

L = list(DictReader(...)) दूसरी तरफ पूरी तरह उपयुक्त है, जब तक कि डिक्ट्स की सूची स्मृति में आराम से फिट हो सके। iter(L) के साथ किसी भी समय "बहुत हल्का और कम ओवरहेड) एक नया" इटेटरेटर "शुरू किया जा सकता है, और नए या मौजूदा लोगों को प्रभावित किए बिना पूरी तरह से या पूरी तरह से उपयोग किया जा सकता है; अन्य पहुंच पैटर्न भी आसानी से उपलब्ध हैं।

जैसा कि कई उत्तरों ने सही टिप्पणी की है, csv के विशिष्ट मामले में आप .seek(0) अंतर्निहित फ़ाइल ऑब्जेक्ट (बल्कि एक विशेष मामला) भी कर सकते हैं। मुझे यकीन नहीं है कि दस्तावेज और गारंटी है, हालांकि यह वर्तमान में काम करता है; यह शायद वास्तव में बड़ी सीएसवी फाइलों के लिए विचार करने योग्य होगा, जिसमें list मैं अनुशंसा करता हूं क्योंकि सामान्य दृष्टिकोण में स्मृति पदचिह्न बहुत बड़ा होगा।

+3

5 एमबी फ़ाइल पर एक csvreader पर मल्टीपासेज कैश करने के लिए 'सूची() 'का उपयोग करके मेरा रनटाइम ~ 12secs से ~ 0.5s तक जाता है। –

0

केवल अगर अंतर्निहित प्रकार ऐसा करने के लिए एक तंत्र प्रदान करता है (उदा। fp.seek(0))।

16

नहीं। पायथन का इटरेटर प्रोटोकॉल बहुत आसान है, और केवल एक एकल विधि (.next() या __next__()) प्रदान करता है, और सामान्य रूप से एक पुनरावर्तक को रीसेट करने की कोई विधि नहीं है।

सामान्य पैटर्न फिर से उसी प्रक्रिया का उपयोग करके एक नया इटरेटर बनाने के लिए है।

आप एक इटरेटर ताकि आप इसकी शुरुआत करने के लिए वापस जा सकते हैं "बंद बचाने" करना चाहते हैं, तो आप भी इटरेटर itertools.tee

+0

जबकि आप .next() विधि का विश्लेषण कर रहे हैं शायद सही है, ओप क्या मांग रहा है पाने के लिए एक काफी सरल तरीका है। – Wilduck

+0

@ विल्डक: मैं आपका जवाब देखता हूं। मैंने अभी पुनरावर्तक प्रश्न का उत्तर दिया, और मुझे 'सीएसवी' मॉड्यूल के बारे में कोई जानकारी नहीं है। उम्मीद है कि दोनों उत्तर मूल पोस्टर के लिए उपयोगी हैं। – u0b34a0f6ae

+0

कड़ाई से, इटरेटर प्रोटोकॉल को भी '__iter__' की आवश्यकता होती है। यही है, इटेटर को भी पुनरावृत्तियों की आवश्यकता होती है। –

25

का उपयोग करके कांटा हो सकता है आप '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} 

फिर।

ऐसा लगता है कि आप जिस कार्यक्षमता की तलाश में हैं। मुझे यकीन है कि इस दृष्टिकोण से जुड़े कुछ चाल हैं कि मुझे हालांकि पता नहीं है। @ ब्रायन ने बस एक और डिक्ट्रेडर बनाने का सुझाव दिया। यदि आप पहली पाठक फ़ाइल को पढ़ने के माध्यम से आधे रास्ते हैं, तो यह काम नहीं करेगा, क्योंकि आपके नए पाठक के पास फ़ाइल में कहीं भी अप्रत्याशित कुंजी और मूल्य होंगे।

+0

यह मेरे सिद्धांत ने मुझे बताया, यह देखने के लिए अच्छा लगा कि मैंने क्या सोचा था, करता है। –

+0

@ विल्डक: डिक्ट्रेडर के दूसरे उदाहरण के साथ आप जो व्यवहार कर रहे हैं वह तब नहीं होगा जब आप एक नया फाइल हैंडल करते हैं और दूसरे डिक्ट्रेडर को पास करते हैं, है ना? – user248237dfsf

+0

यदि आपके पास दो फ़ाइल हैंडलर हैं तो वे स्वतंत्र रूप से व्यवहार करेंगे, हां। – Wilduck

2

हालांकि कोई इटरेटर रीसेट नहीं है, पाइथन 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] 
10

उपरोक्त एलेक्स मार्टेलि और वाइल्डक द्वारा वकालत के रूप में .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) 
6

हाँ, यदि आप 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 
+0

'itertools.cycle' जैसे सरणी के माध्यम से' nditer' चक्र 'कर सकते हैं? – LWZ

+0

@LWZ: मुझे ऐसा नहीं लगता है, लेकिन आप कोशिश कर सकते हैं: 'अगला()' और 'स्टॉपइटरेशन' अपवाद पर 'रीसेट() 'करें। –

+0

... इसके बाद 'अगला() ' –

0

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

यह शायद मूल प्रश्न के लिए ओर्थोगोनल है, लेकिन एक एक समारोह है कि इटरेटर रिटर्न में इटरेटर लपेट सकता है।

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) 

यह और एक जनरेटर के लिए

0

list(generator()) रिटर्न सभी शेष मूल्यों क्या करने की जरूरत होगी कैशिंग कि टी (एन प्रतियां) या सूची (1 प्रतिलिपि) से बचने के लिए लगता है प्रभावी रूप से यह रीसेट करता है अगर यह फंस नहीं है ।

0

छोटी फ़ाइलों के लिए, आप 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 के रूप में बड़ी फ़ाइलों को इस उपकरण को लागू करने से सावधान रहें।

0

समस्या

मेरे पास पहले भी यही समस्या है। मेरे कोड का विश्लेषण करने के बाद, मुझे एहसास हुआ कि लूप के अंदर इटरेटर को रीसेट करने का प्रयास थोड़ा जटिलता बढ़ाता है और यह कोड को थोड़ा बदसूरत बनाता है।

समाधान

ओपन फ़ाइल और स्मृति में एक चर के लिए पंक्तियों को बचाने के।

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

अब आप पंक्तियों पुनरावर्तक के साथ काम कर के बिना अपने दायरे में कहीं भी के माध्यम से लूप कर सकते हैं।