2013-02-10 35 views
8

पर एक फ़ाइल बंद करें मैंने एक इटरेटर क्लास लिखा है जो __init__ में एक फ़ाइल खोलता है।पायथन कस्टम इटरेटर: StopIteration

def __init__(self, path): 
    self.file = open(path, "r") 

पुनरावृत्ति समाप्त होने पर मैं स्वचालित रूप से उस फ़ाइल को कैसे बंद करूं?

पूरा वर्ग:

class Parse(object): 
    """A generator that iterates through a CC-CEDICT formatted file, returning 
    a tuple of parsed results (Traditional, Simplified, Pinyin, English)""" 
    def __init__(self, path): 
     self.file = open(path, "r") 

    def __iter__(self): 
     return self 

    def __is_comment(self, line): 
     return line.startswith("#") 

    def next(self): 
     #This block ignores comments. 
     line = self.file.readline() 
     while line and self.__is_comment(line): 
      line = self.file.readline() 

     if line: 
      working = line.rstrip().split(" ") 
      trad, simp = working[0], working[1] 
      working = " ".join(working[2:]).split("]") 
      pinyin = working[0][1:] 
      english = working[1][1:] 
      return trad, simp, pinyin, english 

     else: 
      raise StopIteration() 
+0

क्या आप पुनरावृत्ति भाग साझा कर सकते हैं? क्या आप '.next() 'या' .__ अगली __() 'विधि का उपयोग करते हैं या जनरेटर विधि' __iter__' है? –

+0

@MartijnPieters मैं पूरी बात साझा करूंगा – jsj

उत्तर

10

पूरी बात लिखने के लिए एक ही स्थान पर उद्घाटन और यात्रा रखने के लिए होगा एक बेहतर तरीका:

class Parse(object): 
    """A generator that iterates through a CC-CEDICT formatted file, returning 
    a tuple of parsed results (Traditional, Simplified, Pinyin, English)""" 
    def __init__(self, path): 
     self.path = path 

    def __is_comment(self, line): 
     return line.startswith("#") 

    def __iter__(self): 
     with open(self.path) as f: 
      for line in f: 
       if self.__is_comment(line): 
        continue 

       working = line.rstrip().split(" ") 
       trad, simp = working[0], working[1] 
       working = " ".join(working[2:]).split("]") 
       pinyin = working[0][1:] 
       english = working[1][1:] 
       yield trad, simp, pinyin, english 

यह फ़ाइल को तब तक खोलने का इंतजार करेगा जब तक कि आपको वास्तव में इसकी आवश्यकता न हो, और इसे पूरा होने पर स्वचालित रूप से बंद कर दिया जाएगा। यह भी कम कोड है।

यदि आप वास्तव में "जेनरेटर शानदार हैं" में शामिल होना चाहते हैं! मानसिकता:

def skip_comments(f): 
    for line in f: 
     if not.startswith('#'): 
      yield line 

... 

    def __iter__(self): 
     with open(self.path) as f: 
      for line in skip_comments(f): 
       working = .... 
+0

और जब जनरेटर विधि गुंजाइश से बाहर हो जाती है, तो यह स्वचालित रूप से साफ हो जाती है, फ़ाइल बंद होती है, और सभी खुश और बेवकूफ हैं! जनरेटर के रूप में –

+1

'__iter__' वास्तव में जाने का सबसे अच्छा तरीका है। –

+0

केवल दोष: यदि आप '.next()' विधि तक पहुंचना चाहते हैं तो आपको इसे 'iter()' पर कॉल करने की आवश्यकता है। छोटा, शायद ओपी के लिए कोई मुद्दा नहीं है। –

1

आप स्पष्ट रूप से जैसे ही StopIteration उठाया है इसे बंद करने की जरूरत है। इस मामले में, जब आप StopIteration स्वयं उठाते हैं तो बस .close() पर कॉल करें।

def next(self): 
    #This block ignores comments. 
    line = self.file.readline() 
    while line and self.__is_comment(line): 
     line = self.file.readline() 

    if line: 
     working = line.rstrip().split(" ") 
     trad, simp = working[0], working[1] 
     working = " ".join(working[2:]).split("]") 
     pinyin = working[0][1:] 
     english = working[1][1:] 
     return trad, simp, pinyin, english 

    else: 
     self.file.close() 
     raise StopIteration() 

के बाद से अपने .next() विधि में कोई अन्य कोड एक StopIteration इस पर्याप्त को चालू कर सकते।

आप अपनी खुद की .next() अंदर एक और पुनरावर्तक पर उपयोग next() किया था, तो आप एक except StopIteration: हैंडलर के साथ StopIteration पकड़ने और अपवाद reraise होगा।

यह केवलStopIteration केस संभालता है। यदि आप अन्य परिस्थितियों को संभालना चाहते हैं (इटरेटर को थका नहीं) तो आपको उस स्थिति को अलग से संभालना होगा। अपनी कक्षा को Context Managerके साथ-साथ इसके साथ मदद कर सकता है। इसके बाद आपके इटरेटर के उपयोगकर्ता with कथन में ऑब्जेक्ट का उपयोग करने से पहले ऑब्जेक्ट का उपयोग करेंगे, और जब with सूट से बाहर निकलता है तो फ़ाइल को बंद किया जा सकता है। आप अपने इटरेटर चिह्नित करने के लिए चाहते हो सकता है के रूप में उस मामले में 'पूर्ण' के साथ-साथ:

_closed = False 

def next(self): 
    if self._closed: 
     raise StopIteration 

    line = self.file.readline() 
    while line and self.__is_comment(line): 
     line = self.file.readline() 

    if line: 
     working = line.rstrip().split(" ") 
     trad, simp = working[0], working[1] 
     working = " ".join(working[2:]).split("]") 
     pinyin = working[0][1:] 
     english = working[1][1:] 
     return trad, simp, pinyin, english 

    else: 
     self.file.close() 
     self._closed = True 
     raise StopIteration() 

def __enter__(self): 
    return self 

def __exit__(self, type_, value, tb): 
    self.file.close() # multiple calls to .close() are fine 
    self._closed = True 
+0

तो जब मैं मुख्य से पुनरावृत्ति तोड़ता हूं तो क्या होता है, और क्या कभी नहीं पहुंचाया जाएगा? – jsj

+0

@ trideceth12: उस बिंदु पर आपका पुनरावर्तक कभी भी 'स्टॉपइटरेशन' नहीं उठाएगा। यदि आप उस स्थिति को पकड़ना चाहते हैं, तो अपनी कक्षा को एक संदर्भ प्रबंधक * भी बनाएं *। –