Message233903
If a generator has its close() method called before any items are requested from it, a finally block in the generator function will not be executed.
I encountered this when wrapping an open file to alter the result of iterating over it. Using a generator function with a try/finally block seemed like a simple way of acheiving this. Here's an example that logs each line as it's read:
def logged_lines(f):
try:
for line in f:
logging.warning(line.strip())
yield line
finally:
logging.warning('closing')
f.close()
If the generator is created and closed immediately, the underlying file-like object is left open:
>>> f = urlopen('https://docs.python.org/')
>>> lines = logged_lines(f)
>>> lines.close()
>>> f.closed
False
But once the first item is requested from the generator, close() will trigger cleanup:
>>> lines = logged_lines(f)
>>> next(lines)
WARNING:root:<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"\n'
>>> lines.close()
WARNING:root:closing
>>> f.closed
True
Having read the documentation for yield expressions, I don't believe this behaviour to be non-conformant - but it still seems like a bit of a gotcha to me. Should this usage be warned against? |
|
Date |
User |
Action |
Args |
2015-01-13 07:35:46 | sjdrake | set | recipients:
+ sjdrake, docs@python |
2015-01-13 07:35:46 | sjdrake | set | messageid: <1421134546.13.0.154248882029.issue23227@psf.upfronthosting.co.za> |
2015-01-13 07:35:46 | sjdrake | link | issue23227 messages |
2015-01-13 07:35:44 | sjdrake | create | |
|