Python ValueError:对上下文管理器范围内的已关闭文件执行I/O操作
我读过很多类似的问题,但大多数问题都是通过修正缩进来解决的,所以要么我不懂,要么有一些简单的方法来修正我的问题,但我不认为这与识别有关。 因此,我有一个函数,它基本上使用两个*.txt文件执行一些操作,并返回一个名为Python ValueError:对上下文管理器范围内的已关闭文件执行I/O操作,python,python-3.x,python-3.6,with-statement,contextmanager,Python,Python 3.x,Python 3.6,With Statement,Contextmanager,我读过很多类似的问题,但大多数问题都是通过修正缩进来解决的,所以要么我不懂,要么有一些简单的方法来修正我的问题,但我不认为这与识别有关。 因此,我有一个函数,它基本上使用两个*.txt文件执行一些操作,并返回一个名为的生成器对象tuples,其中包含一些我需要稍后查找的信息 def master_reader(file1, file2): with open(file1, "r", encoding="utf-8") as genomas: with open(file2
的生成器对象tuples
,其中包含一些我需要稍后查找的信息
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.
原始异常是:
回溯(最近一次呼叫最后一次):
文件“lib.py”,第204行,在
印刷品(valor_caracteristica(“TCT”、“Luna Lovegood”、master_reader(“genomas.txt”、“listas.txt”))
文件“lib.py”,第194行,在valor_caracteristica中
a=next(过滤器(lambda x:x.nombre==nombre,文件))
文件“lib.py”,第185行,在
f=(f中直线A的人物(直线A,l)
ValueError:对关闭的文件执行I/O操作。
map()
返回迭代器。只有当您在map()
对象上循环时,它才会将函数实际应用于输入iterable的下一个元素
因此,在您开始使用map
对象和底层生成器表达式之前,不会从文件中读取任何数据。您在函数外部执行此操作,此时文件已经关闭,因为return f
语句退出了函数并扩展了上下文
解决方法是要么不使用像map()
这样的惰性对象,要么将函数设置为生成器函数。在处理完文件之前,后者不会退出(并用块发出退出上下文的信号)
这可以非常简单地通过使用的收益率来实现:
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
>>从contextlib导入contextmanager
>>>@contextmanager
... def democtx():
... 打印('输入上下文')
... 产量
... 打印('退出上下文')
...
>>>def return_map():
... 使用democtx():
... 返回图(λx:x**2,范围(3))
...
>>>def yield_from_map():
... 使用democtx():
... 地图收益率(λx:x**2,范围(3))
...
>>>示例1=返回\u映射()
进入上下文
退出上下文
>>>示例2=从图()中得出的产量
>>>下一步(示例2)
进入上下文
0
>>>下一步(示例2)
1.
>>>下一步(示例2)
4.
>>>下一步(示例2)
退出上下文
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
停止迭代
请注意,对于
example1
来说,上下文是如何在返回时立即退出的,而example2
直到迭代开始才打开上下文,直到我们在map()
对象上完全迭代后才关闭上下文。因为您使用的是python3
,map
构造返回生成器,这些生成器被延迟计算。因此,当计算生成器f
时,文件处理程序可能已经关闭(打开文件的上下文管理器会确保这一点)
解决方案是要么评估其中的地图,要么根本不使用它们,然后使用列表理解
return list(f) # evaluate the map statement therein.
# or you should just return a generator as @MartinPieters suggested.
谢谢你的详细解释,Martijn!直到现在,我才意识到在上下文管理器中使用惰性对象的含义。