[Python-ideas] With clauses for generator expressions
Phil Connell
pconnell at gmail.com
Thu Nov 15 12:22:51 CET 2012
On Thu, Nov 15, 2012 at 03:11:07AM -0800, Andrew Barnert wrote:
> > From: Phil Connell <pconnell at gmail.com>
> > Sent: Thu, November 15, 2012 1:24:52 AM
> >
> > On Wed, Nov 14, 2012 at 07:44:44PM -0800, Andrew Barnert wrote:
> > >
> > > upperlines = (lines.upper() for line in file with open('foo', 'r') as
> >file)
> >
> > While this looks very clean, how do you propose the following should be
> >written
> > as a generator expression?
> >
> > def foo():
> > with open('foo') as f:
> > for line in f:
> > if 'bar' in line:
> > yield line
>
> Exactly as you suggest (quoting you out of order to make the answer clearer):
>
> > (line
> > for line in f
> > if bar in 'line'
> > with open('foo') as f)
>
>
> > An obvious suggestion is as follows, but I'm not totally convinced about the
> > out-of-order with, for and if clauses (compared with the equivalent
> generator)
>
>
> The clauses have *always* been out of order. In the function, the "if" comes
> between the "for" and the yield expression. In the expression, the "for" comes
> in between. If the clause order implies the statement order (I would have put it
> in terms of the clause structure implying the scoping, but they're effectively
> the same idea), then our syntax has been wrong since list comprehensions were
> added in 2.0. So, I think (and hope!) that implication was never intended.
I was mostly playing devil's advocate :)
In my experience, the ordering of comprehension clauses is already a source of
confusion for those new to the language. So, if it's not obvious where the "if"
should come it may well make matters worse in this regard (but I wouldn't say
that this is enough to kill the proposal).
>
> Which means the only question is, which one looks more readable:
>
> 1. (foo(line) for line in baz(f) if 'bar' in line with open('foo') as f)
> 2. (foo(line) for line in baz(f) with open('foo') as f if 'bar' in line)
> 3. (foo(line) with open('foo') as f for line in baz(f) if 'bar' in line)
To me, 1 feels like it captures the semantics the best - the "with" clause is
tacked onto the generator expression "(foo(line) ... for ... if)" and applies
to the whole of that expression.
Cheers,
Phil
>
> Or, in the trivial case (where versions 1 and 2 are indistinguishable):
>
> 1. (line for line in f with open('foo') as f)
> 2. (line for line in f with open('foo') as f)
> 3. (line with open('foo') as f for line in f)
>
> My own intuition is that 1 is the clearest, and 3 by far the worst. So, that's
> why I proposed order 1. But I'm not at all married to it.
More information about the Python-ideas
mailing list