在不关闭文件的情况下调用新函数

call a new function without closing the file

提问人:invalid syntax 提问时间:10/30/2023 最后编辑:invalid syntax 更新时间:10/30/2023 访问量:66

问:

我有一个打开 csv 文件的方法和另一个我想用来处理这个文件的方法 - 但我也需要它来处理不同类型的对象,所以我想将其保留为一个独立的方法。

import csv

class Loader():

    def load_from_csv(self, csv_path: str):

        with open(csv_path, mode='r', encoding='utf-8') as file:
            reader = csv.DictReader(file)
            return self._read_and_yield(reader)
    
    @classmethod
    def _read_and_yield(cls,reader):
        for row in reader:
            yield(row)

loader = Loader()
for row in loader.load_from_csv('sample.csv'):
    print(row)

但是我明白了,因为当我调用该方法时,文件似乎被关闭了。在这里,它只产生行,但想象一下我必须执行更多操作的情况:我应该对每种类型的文件(即 )重复此过程。ValueError: I/O operation on closed file_read_and_yieldread_from_excel

我应该如何处理?

Python 迭代器 产量

评论

0赞 John Gordon 10/30/2023
如果是类方法,为什么第一个参数是?_read_and_yield()self
0赞 invalid syntax 10/30/2023
对不起,我的错(我编辑了问题)。无论如何,这似乎不是问题。
1赞 jasonharper 10/30/2023
在调用方有机会迭代返回的生成器之前,该块将关闭文件。一个可能的解决方法是让自己成为生成器 - 带有 s 的循环将在 ,因此在遍历整个文件之前,文件不会被关闭。withload_from_csv()load_from_csv()yieldwith
1赞 Tom Karzes 10/30/2023
当您调用时,它不会关闭。当您执行退出块的语句时,它会关闭。如果您不希望它在您返回时自动关闭文件,请不要使用 .只需致电 .但是在某个时候,您应该打电话关闭它。_read_and_yieldreturnwithwithopenclose
1赞 rioV8 10/30/2023
它更像是一个而不是一个@staticmethod@classmethod

答:

1赞 blhsing 10/30/2023 #1

当封闭函数返回时,该模块将关闭文件,因此迭代器无法再从文件中读取。withcsv.DictReader

相反,您可以从上下文管理器中生成生成的值,以便在调用方对其进行迭代时文件句柄可以保持打开状态:load_from_csv_read_and_yield

with open(csv_path, mode='r', encoding='utf-8') as file:
    reader = csv.DictReader(file)
    yield from self._read_and_yield(reader)
1赞 Codist 10/30/2023 #2

您可以考虑将 Loader 类重写为上下文管理器。

像这样的东西:

from csv import DictReader

class Loader:
    def __init__(self, filename):
        self._filename = filename
    def __enter__(self):
        self._fd = open(self._filename, "r", encoding="utf-8", newline="")
        return self
    def __exit__(self, *_):
        self._fd.close() #type: ignore
    def row(self):
        yield from DictReader(self._fd) #type: ignore

with Loader("foo.csv") as loader:
    for r in loader.row():
        print(r)