9

我写了一个迭代器类,它在它的__init__.

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

2 回答 2

16

编写整个内容的更好方法是将开头和迭代保留在一个地方:

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 = ....
于 2013-02-10T13:15:11.327 回答
1

您需要在StopIteration提出后立即明确关闭它。在这种情况下,只需.close()在你自己加注时跟StopIteration注。

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()方法中没有其他代码可以触发StopIterationthis 就足够了。

如果您确实next()在自己内部的另一个迭代器上使用过,则必须使用处理程序.next()捕获并重新引发异常。StopIterationexcept StopIteration:

这只处理这种情况StopIteration。如果您想处理其他情况(不耗尽迭代器),您需要单独处理该情况。让你的班级成为一个上下文管理器 可以帮助你。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
于 2013-02-10T13:01:59.407 回答