ValueError: I/O operation on closed file within context manager scope

ValueError: I/O operation on closed file within context manager scope

我读过很多类似的问题,但其中大部分都是通过修复缩进来解决的,所以要么我一无所知,要么有一些简单的方法可以解决我的问题,但我认为这与标识无关。 所以我有这个函数,它基本上使用两个 *.txt 文件和 returns namedtuples 的生成器对象执行几个操作,其中包含一些我需要稍后查找的信息。

def master_reader(file1, file2):
    with open(file1, "r", encoding="utf-8") as genomas:
        with open(file2, "r", encoding="utf-8") as listas:
            l = parser_listas(listas)
            f = parser_genomas(genomas)
            f = map(intifier, f)
            f = (people_maker(linea, l) for linea in f)
            f = map(genotipo_getter, f)
            f = map(fen_getter, f)
            return f

当我调用它并将其分配给 variable.But 时一切正常它:

print(valor_caracteristica("TCT", "Luna  Lovegood", master_reader("genomas.txt", "listas.txt")))

但是我遇到了这个异常:

Original exception was:
Traceback (most recent call last):
  File "lib.py", line 204, in <module>
    print(valor_caracteristica("TCT", "Luna  Lovegood", master_reader("genomas.txt", "listas.txt")))
  File "lib.py", line 194, in valor_caracteristica
    a = next(filter(lambda x: x.nombre == nombre, file))
  File "lib.py", line 185, in <genexpr>
    f = (people_maker(linea, l) for linea in f)
ValueError: I/O operation on closed file.

map() returns 一个迭代器。只有当你遍历一个 map() 对象时,它才会真正将该函数应用于输入可迭代对象的下一个元素。

因此,在您开始使用 map 对象和底层生成器表达式之前,没有从您的文件中读取任何数据。您在函数之外执行此操作,此时文件已经关闭,因为 return f 语句退出了函数并扩展了上下文。

解决方法是不使用像 map() 这样的惰性对象,或者使您的函数成为 生成器函数 。后者不会退出(并向 with 块发出信号以退出上下文),直到您完成文件。

这可以通过使用 yield from:

非常简单地完成
def master_reader(file1, file2):
    with open(file1, "r", encoding="utf-8") as genomas:
        with open(file2, "r", encoding="utf-8") as listas:
            l = parser_listas(listas)
            f = parser_genomas(genomas)
            f = map(intifier, f)
            f = (people_maker(linea, l) for linea in f)
            f = map(genotipo_getter, f)
            yield from map(fen_getter, f)

yield from 保持生成器打开直到底层 map() 对象引发 StopIteration.

一个说明差异的快速演示:

>>> from contextlib import contextmanager
>>> @contextmanager
... def democtx():
...     print('Entering the context')
...     yield
...     print('Exiting the context')
...
>>> def return_map():
...     with democtx():
...         return map(lambda x: x**2, range(3))
...
>>> def yield_from_map():
...     with democtx():
...         yield from map(lambda x: x**2, range(3))
...
>>> example1 = return_map()
Entering the context
Exiting the context
>>> example2 = yield_from_map()
>>> next(example2)
Entering the context
0
>>> next(example2)
1
>>> next(example2)
4
>>> next(example2)
Exiting the context
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

注意 example1 上下文如何在 return 后立即退出,而 example2 直到迭代开始才打开上下文,并且直到我们迭代进入才关闭上下文填满 map() 对象。

由于您使用的是 Python 3map 构造了 returns 生成器,这些生成器是延迟计算的。因此,当生成器 f 被评估时,文件处理程序已经关闭(打开文件的上下文管理器确保了这一点)。

解决方案是评估其中的地图,或者根本不使用它们,并使用列表理解。

return list(f) # evaluate the map statement therein.

# or you should just return a generator as @MartinPieters suggested.