I just saw the following code:
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)
What happens in this case? Is the context manager smart enough to know that linegen
still has a reference to the file handle, such that it's not closed when the context is left? Or is this potentially unsafe?
This is one of those breaking changes in Python 3.
Your question title (Taking a generator ...) implies you are reading it as Python 3 code.
But the statement
from __future__ import print_function
implies it was written for Python 2
In Python 2, map
returns an actual list - and thus this code is both perfectly safe and extrmely sensible (i.e open a file, read all lines,s tripping them as you go, then close the file)
In [2]: with open('README.md','r') as f:
...: lines = map(str.strip, f)
...:
In [3]: lines
Out[3]:
['ASM',
'============',
'',
In Python 3, the same code throws an exception
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.
If you want a version-safe implementation of this you need to either convert the generator to a list
lines = list(map(str.strip, f))
or just use a list comprehension
lines = [l.strip() for l in f]