क्या पायथन में पुनरावृत्तियों को रीसेट किया जा सकता है?


130

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


जवाबों:


84

मैं कई उत्तरों को पुनरावृति का सुझाव देता देख रहा हूं , लेकिन इसके लिए डॉक्स में एक महत्वपूर्ण चेतावनी की अनदेखी कर रहा है:

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

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

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

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


6
5 list()एमबी फ़ाइल पर सीएसवीडर पर कैश मल्टीपज का उपयोग करने से मेरा रनटाइम ~ 12secs से ~ 0.5 s तक चला जाता है।
जॉन मी

33

अगर आपके पास '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 बनाने का सुझाव दिया। यह काम नहीं करेगा यदि आप पहले पाठक फ़ाइल को पढ़ने के माध्यम से आधे रास्ते में हैं, क्योंकि आपके नए पाठक के पास फ़ाइल में आप जहाँ भी हैं वहां से अप्रत्याशित कुंजी और मान होंगे।


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

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

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

24

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

सामान्य पैटर्न के बजाय फिर से एक ही प्रक्रिया का उपयोग करके एक नया पुनरावृत्ति बनाना है।

यदि आप एक पुनरावृत्‍ति को "सेव" करना चाहते हैं ताकि आप इसकी शुरुआत में वापस जा सकें, तो आप उपयोग करके इट्रियर्स को भी निकाल सकते हैं itertools.tee


1
जब आप .next () विधि का विश्लेषण कर रहे हैं, तो शायद सही है, ऑप जो पूछ रहा है उसे प्राप्त करने का एक सरल तरीका है।
Wilduck

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

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

11

हां , यदि आप 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?
LWZ

1
@LWZ: मुझे ऐसा नहीं लगता है, लेकिन आप कर सकते हैं और एक पर अपवाद एक कर । try:next()StopIterationreset()
अगली सूचना तक रोक दिया गया।


यह वही है जिसे मैं देख रहा था !
श्रीराम

1
ध्यान दें कि "ऑपरेंड्स" की सीमा यहां 32 है: stackoverflow.com/questions/51856685/…
सिमोन

11

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

5

यह शायद मूल प्रश्न के लिए रूढ़िवादी है, लेकिन एक पुनरावृत्ति करने वाले फ़ंक्शन में पुनरावृत्ति को लपेट सकता है।

def get_iter():
    return iterator

पुनरावृत्ति रीसेट करने के लिए बस फ़ंक्शन को फिर से कॉल करें। यह निश्चित रूप से तुच्छ है यदि फ़ंक्शन जब उक्त फ़ंक्शन कोई तर्क नहीं लेता है।

इस मामले में कि फ़ंक्शन को कुछ तर्कों की आवश्यकता होती है, मूल बंद करने वाले के बजाय पारित होने के लिए एक क्लोजर बनाने के लिए फंक्शनल टूल का उपयोग करें।

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

ऐसा लगता है कि कै से बचने के लिए टी (एन प्रतियां) या सूची (1 प्रति) की आवश्यकता होगी


3

छोटी फ़ाइलों के लिए, आप उपयोग करने पर विचार कर सकते हैं 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में लिपटा हुआ है seekableseek()विधि रीसेट / 0 स्थिति (3) को इटरेटर रिवाइंड करने के लिए प्रयोग किया जाता है।

नोट: मेमोरी खपत पुनरावृत्ति के साथ बढ़ती है, इसलिए इस उपकरण को बड़ी फ़ाइलों पर लागू करने से सावधान रहें, जैसा कि डॉक्स में दर्शाया गया है


2

हालांकि कोई पुनरावृत्ति रीसेट नहीं है, अजगर 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]

1

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

1

list(generator()) एक जनरेटर के लिए सभी शेष मान लौटाता है और प्रभावी रूप से रीसेट करता है यदि यह लूप नहीं है।


1

संकट

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

उपाय

फ़ाइल खोलें और मेमोरी में पंक्तियों को एक चर में सहेजें।

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

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


1

एक संभव विकल्प का उपयोग करना है itertools.cycle(), जो आपको बिना किसी चाल के अनिश्चित काल तक पुनरावृति करने की अनुमति देगा .seek(0)

iterDic = itertools.cycle(csv.DictReader(open('file.csv')))

1

मैं इसी मुद्दे पर आ रहा हूं - जब मैं tee()समाधान पसंद करता हूं, तो मुझे नहीं पता कि मेरी फाइलें कितनी बड़ी होने जा रही हैं और स्मृति पहले एक का उपभोग करने के बारे में चेतावनी दे रही हैं, जबकि दूसरे मुझे उस पद्धति को अपनाने से रोक रहे हैं।

इसके बजाय, मैं iter()बयानों का उपयोग करके और अपने शुरुआती रन-थ्रू के लिए पहले का उपयोग करके पुनरावृत्तियों की एक जोड़ी बना रहा हूं , अंतिम रन के लिए दूसरे पर स्विच करने से पहले।

तो, एक तानाशाह पाठक के मामले में, अगर पाठक का उपयोग कर परिभाषित किया गया है:

d = csv.DictReader(f, delimiter=",")

मैं इस "विनिर्देश" से पुनरावृत्तियों की एक जोड़ी बना सकता हूं - उपयोग करना:

d1, d2 = iter(d), iter(d)

मैं तब अपना प्रथम-पास कोड चला सकता हूं d1, इस ज्ञान में सुरक्षित कि दूसरा पुनरावृत्त d2उसी मूल विनिर्देश से परिभाषित किया गया है।

मैंने यह पूरी तरह से परीक्षण नहीं किया है, लेकिन यह डमी डेटा के साथ काम करता है।



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 
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.