ValueError:上下文管理器范围内的已关闭文件上的I / O操作

时间:2017-10-04 13:41:38

标签: python python-3.x python-3.6 with-statement contextmanager

我已经阅读了很多类似的问题,但是他们中的大多数都是通过修复缩进来解决的,所以要么我无能为力,要么有一些简单的方法来解决我的问题,但我不认为这是关于身份的。 所以我有这个功能,基本上使用两个* .txt文件执行一些操作,并返回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

当我调用它并将其分配给变量时,事情就是一切正常。但是我需要将它用作参数,所以每次我需要它时我都可以调用它来执行我需要执行的一些查询:

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.

2 个答案:

答案 0 :(得分:3)

map()返回一个迭代器。只有当您遍历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如何在返回时立即退出上下文,而example2在迭代开始之前没有打开上下文,并且在我们完全遍历{{1}之前没有关闭上下文对象。

答案 1 :(得分:1)

由于您正在使用def get_value_idx(value): model = QSqlTableModel() model.setTable("pvalues") model.setFilter("val = '%s'" % (value)) model.select() count = model.rowCount() if count >= 1: l = list() for n in range(count): id = model.record(n).value('id') l.append(id) return l # return id list if count == 0: return -1 # return id that shows error Python 3构造会返回生成器,这些生成器会被延迟评估。因此,当评估生成器map时,文件处理程序已经关闭(打开文件的上下文管理器确保了这一点)。

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

f