将生成器从上下文管理器中取出

时间:2016-07-14 14:58:07

标签: python generator contextmanager

我刚刚看到以下代码:

from __future__ import print_function
from future_builtins import map # generator

with open('test.txt', 'r') as f:
    linegen = map(str.strip, f)

# file handle should be closed here

for line in linegen:
    # using the generator now
    print(line)

在这种情况下会发生什么?上下文管理器是否足够聪明,知道linegen仍然具有对文件句柄的引用,以便在保留上下文时它不会关闭?或者这可能不安全吗?

1 个答案:

答案 0 :(得分:2)

这是Python 3中的重大变化之一。

您的问题标题(使用生成器 ...)意味着您正在将其作为Python 3代码阅读。

但声明

from __future__ import print_function

暗示它是为Python 2编写的

在Python 2中,map返回一个实际的列表 - 因此这段代码非常安全且非常合理(即打开一个文件,读取所有行,然后跳转它们,然后关闭文件)

In [2]: with open('README.md','r') as f:
   ...:     lines = map(str.strip, f)
   ...:     
In [3]: lines
Out[3]: 
['ASM',
 '============',
 '',

在Python 3中,相同的代码抛出异常

In [1]: with open('README.md','r') as f:
    lines = map(str.strip, f)
   ...:     
In [2]: lines
Out[2]: <map at 0x7f4d393c3ac8>
In [3]: list(lines)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-3-2666a44c63b5> in <module>()
----> 1 list(lines)

ValueError: I/O operation on closed file.

如果您想要版本安全的实现,您需要将生成器转换为列表

lines = list(map(str.strip, f))

或只使用列表理解

lines = [l.strip() for l in f]