【问题标题】:Is there a way to decouple a csv generator in my code that doesn't close the file?有没有办法在我的代码中解耦不关闭文件的 csv 生成器?
【发布时间】:2020-07-16 17:41:16
【问题描述】:

我想编写以下代码来将数据馈送与我的程序的其余部分分离,但它不会抛出错误 - “ValueError: I/O operation on closed file。”

class Feed:
    def __init__(self, data_loc=None):
        self.data_loc = data_loc
        with open(self.data_loc, newline='') as f:
            self.reader = csv.reader(f)

    def get_next_tick(self):
        return next(self.reader)


raw_data_loc = '{path to file}'

feed = Feed(data_loc=raw_data_loc)

print(feed.get_next_item())

我知道在 init 运行后文件关闭并因此出现错误,但是有没有办法在我的代码中实现这个 csv 生成器的分离?

【问题讨论】:

  • 您想在 get_next_tick 方法中明确不再使用“with open()”语句吗?
  • 在构造函数中你可以做self.reader = csv.reader(open(self.data_loc, 'r', newline=''))
  • with 语句会自动关闭文件……这就是使用文件对象作为上下文管理器的全部意义所在。如果您不想关闭它,请不要这样做。
  • 谢谢大家,会仔细研究一下,看看它是否能解决。 @Jonas,不,我不反对在 get_next_tick 方法中使用它。
  • @AndrejKesely 成功了。谢谢!

标签: python python-3.x csv


【解决方案1】:

扩展我的评论,您可以像这样将Feed 实现为上下文管理器:

class Feed:
    def __init__(self, *args, **kwargs):
        self.file_obj = open(*args, **kwargs)
        self.reader = csv.reader(self.file_obj)
    def __enter__(self):
        return self
    def __exit__(self, type, value, traceback):
        self.close()
    def get_next_tick(self):
        return next(self.reader)
    def close(self):
        self.file_obj.close()

要打印提要的第一行,我们可以执行以下操作:

with Feed('feed.csv') as feed:
    print(feed.get_next_tick())

因为我们使用了上下文管理器,所以即使提要为空并引发StopIteration 异常,也会调用__exit__ 方法。

如果您希望能够迭代提要,可以添加 __next____iter__ 方法,如下所示:

class Feed:
    def __init__(self, *args, **kwargs):
        self.file_obj = open(*args, **kwargs)
        self.reader = csv.reader(self.file_obj)
    def __enter__(self):
        return self
    def __exit__(self, type, value, traceback):
        self.close()
    def __next__(self):
        return self.get_next_tick()
    def __iter__(self):
        return self
    def get_next_tick(self):
        return next(self.reader)
    def close(self):
        self.file_obj.close()

这将允许您循环访问您的提要,甚至直接调用next(feed),例如:

with Feed('feed.csv') as feed:
    for item in feed:
        print(item)

Python Tips 有一个很棒的chapter on using Context Managers,在PEP343 中介绍过。

【讨论】:

    猜你喜欢
    • 2017-12-27
    • 2012-05-17
    • 2011-07-07
    • 2021-02-22
    • 2013-02-13
    • 2011-03-15
    • 2015-05-26
    • 2010-09-07
    • 2021-04-13
    相关资源
    最近更新 更多