[Python-ideas] With clauses for generator expressions
Mathias Panzenböck
grosser.meister.morti at gmx.net
Fri Nov 16 05:33:18 CET 2012
Just throwing random syntax variations on the wall to see what/if anything sticks (because I think
the "as file"-assignment serves no purpose here):
upperlines = (lines.upper() for line in with open('foo', 'r'))
upperlines = (lines.upper() for line with open('foo', 'r'))
upperlines = (lines.upper() with for line in open('foo', 'r'))
Or should the for loop check if there are __enter__ and __exit__ methods and call them? Guess not,
but I thought I just mention it as an alternative.
For now one can do this, which is functional equivalent but adds the overhead of another generator:
def managed(sequence):
with sequence:
for item in sequence:
yield item
upperlines = (lines.upper() for line in managed(open('foo', 'r')))
You could even call this helper function "with_", if you like.
Or write a helper like this:
def iterlines(filename,*args,**kwargs):
with open(filename,*args,**kwargs) as f:
for line in f:
yield line
upperlines = (lines.upper() for line in iterlines('foo', 'r'))
Maybe there should be a way to let a file be automatically closed when EOF is encountered? Maybe an
"autoclose" wrapper object that passes through every method call to the file object but when EOF is
encountered during a read it closes the file object? Then one could write:
upperlines = (lines.upper() for line in autoclose(open('foo', 'r')))
On 11/15/2012 04:44 AM, Andrew Barnert wrote:
> First, I realize that people regularly propose with expressions. This is not the
> same thing.
>
> The problem with the with statement is not that it can't be postfixed
> perl-style, or used in expressions. The problem is that it can't be used with
> generator expressions.
>
> Here's the suggestion:
>
> upperlines = (lines.upper() for line in file with open('foo', 'r') as file)
>
> This would be equivalent to:
>
> def foo():
> with open('foo', 'r') as file:
> for line in file:
> yield line.upper()
> upperlines = foo()
>
> The motivation is that there is no way to write this properly using a with
> statement and a generator expression—in fact, the only way to get this right is
> with the generator function above. And almost nobody ever gets it right, even
> when you push them in the right direction (although occasionally they write a
> complex class that has the same effect).
>
> That's why we still have tons of code like this lying around:
>
> upperlines = (lines.upper() for line in open('foo', 'r'))
>
> Everyone knows that this only works with CPython, and isn't even quite right
> there, and yet people write it anyway, because there's no good alternative.
>
> The with clause is inherently part of the generator expression, because the
> scope has to be dynamic. The file has to be closed when iteration finishes, not
> when creating the generator finishes (or when the generator is cleaned up—which
> is closer, but still wrong).
>
> That's why a general-purpose "with expression" wouldn't actually help here; in
> fact, it would just make generator expressions with with clauses harder to
> parse. A with expression would have to be statically scoped to be general.
>
> For more details, see this:
>
> http://stupidpythonideas.blogspot.com/2012/11/with-clauses-for-generator-expressions.html
More information about the Python-ideas
mailing list