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

Taking a generator out of a context manager

我刚看到下面的代码:

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 仍然有对文件句柄的引用,以便在上下文离开时它不会关闭?还是这可能不安全?

这是 Python 3.

中的重大更改之一

你的问题标题(Taking a generator ...)暗示你正在阅读它作为 Python 3 代码。

但是声明

from __future__ import print_function

表示它是为 Python 2

编写的

在 Python 2 中,map returns 一个实际的列表 - 因此这段代码既非常安全又非常明智(即打开一个文件,读取所有行,跳闸然后关闭文件)

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

在Python3中,同样的代码抛出异常

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.

如果你想要 version-safe 实现它,你需要将生成器转换为列表

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

或者只使用列表理解

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