【问题标题】:Yield & closing file objects properly正确生成和关闭文件对象
【发布时间】:2013-03-26 19:31:43
【问题描述】:

我有以下课程:

class JsonIterator(object):
    def __init__(self,folder):
        self.root = os.path.join(os.getcwd(), folder)
        self.fis = [fi for fi in os.listdir(folder) if "lyrics" in fi]

    def __iter__(self):
        i = 0
        with open(os.path.join(self.root,self.fis[i])) as f:
            yield json.load(f)
        i += 1

它没有按照我想要的方式工作——它似乎没有超出第一个文件。我试过了

def __iter__(self):
    i = 0
    f = open(os.path.join(self.root, self.fis[i]))
    js = json.load(f)
    f.close()
    yield js
    i += 1

但不管怎样,len(list(JsonIterator("path/to/myfolder"))) 给了我1,而且我知道文件夹中有多个文件。当然,另一种选择是

def __iter__(self):
    i = 0
    yield json.load(open(os.path.join(self.root, self.fis[i])))
    i += 1

但是所有那些悬空打开的文件都占用了太多内存,我的进程被杀死了。

那我该怎么办?我想过写一些装饰器,但我真的不明白它们是如何工作的,或者即使它可以解决我的问题。

谢谢!

【问题讨论】:

    标签: python python-2.7


    【解决方案1】:

    你需要遍历self.fis中的文件名:

    class JsonIterator(object):
        def __init__(self,folder):
            self.root = os.path.join(os.getcwd(), folder)
            self.fis = [fi for fi in os.listdir(folder) if "lyrics" in fi]
    
        def __iter__(self):
            for fi in self.fis:
                with open(os.path.join(self.root, fi)) as f:
                    obj = json.load(f)
                yield obj
    

    【讨论】:

    • 我想我会将json.load() 的结果存储在一个变量中,并从上下文管理器外部产生它,以便在函数暂停之前关闭文件;否则,这是最好的答案。
    • @TokenMacGuy:谢谢你的想法!
    【解决方案2】:

    如其他答案中所述,您需要遍历 __iter__() 内的文件列表。这是一个使用生成器表达式做同样事情的等效替代方案:

    def __iter__(self):
        return (json.load(open(os.path.join(self.root, fi))) for fi in self.fis)
    

    The files will be closed automatically when they are garbage collected,假设您使用的是 CPython。

    【讨论】:

    • 文件将在我知道的所有 python 实现中被垃圾收集时自动关闭。只有在使用引用计数的 CPython 中,才会立即收集,而不是在程序退出时或稍后程序遇到负载时收集。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-15
    • 2022-01-23
    • 2020-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多