2017-10-04 56 views
2

我读过很多类似的问题,但其中大多数都是通过修复缩进来解决的,所以要么我不知道,要么有一些简单的修复方法我的问题,但我不认为这是关于身份。 所以我有这个功能,基本上使用两个* .txt文件执行一些操作,并返回一个生成器对象namedtuples与我需要稍后查找的一些信息。ValueError:上下文管理器范围内的关闭文件上的I/O操作

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. 

回答

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没有打开的情况下,直到迭代开始,并没有关闭的背景下,直到我们在map()对象上重复遍历。

+0

感谢您的彻底解释Martijn!直到现在,我还没有意识到在上下文管理器中使用惰性对象的含义。 – Fgbruna

1

由于您正在使用Python 3,map构造函数会返回生成器,这些生成器会进行延迟评估。因此,当生成器f被评估时,文件处理程序已经被关闭(打开文件的上下文管理器确保这一点)。

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

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

# or you should just return a generator as @MartinPieters suggested. 
相关问题