2013-02-10 2 views
8

파일을 여는 iterator 클래스를 작성했습니다 (__init__).Python 커스텀 반복자 : 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()'또는'.__ 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()를 호출해야합니다. 작은 것, 아마 OP를위한 문제점이 아닐 것입니다. –

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을 잡아 예외를 리 레이즈해야 할 것이다.

StopIteration 경우를 처리합니다. 다른 상황 (반복자를 다 써 버리지 않고)을 처리하려면 해당 상황을 별도로 처리해야합니다. 수업을 Context Manager으로 설정하면도 도움이 될 수 있습니다. 반복기 사용자는 반복하기 전에 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 :이 시점에서 반복자는 결코 StopIteration을 발생시키지 않습니다. 이러한 상황을 파악하려면 클래스를 Context Manager *로 만드십시오. –