[Python-ideas] About list comprehension syntax

Arnaud Delobelle arno at marooned.org.uk
Wed May 30 19:31:55 CEST 2007


On 30 May 2007, at 17:30, Terry Reedy wrote:

>
> "Arnaud Delobelle" <arno at marooned.org.uk> wrote in
> message news:8C1BDF74-1DAB-4F64-A28E-16788C48AA95 at marooned.org.uk...
> | Hi
> |
> | List comprehensions (and generator expressions) come in two
> | 'flavours' at the moment:
>
> Actually, you can have 1 to many for clauses and 0 to many if clauses.

That's true.  I use that very seldom in fact.
[...]
> |
> | Now if one wants to write simply filter(p, L) as a list
> | comprehension, one has to write:
> |
> | (3) [x for x in L if p(x)].  This could be called a 'filter
> | comprehension'.
[...]
> | Why not just drop the 'x for' at the start of a 'filter
> | comprehension' (or generator expression)?
>
> Because such micro abbreviations are against the spirit of Python,  
> which is
> designed for readability over writablilty.  Even for a writer, it  
> might
> take as much time to mentally deal with the exception and to simply  
> type
> 'for x', which takes all of a second.

I wasn't suggesting this to save myself from typing 5 characters.   
You'll find it strange but I actually find [x in L if p(x)] more  
readable than [x for x in L if p(x)].  To me it says that I'm  
filtering, not mapping.

> Also, this breaks the mapping
> between for/if statements and clauses and makes the code ambiguous  
> for both
> humans and the parser
>

By ambiguous do you mean 'difficult to parse'?  I didn't think it was  
ambiguous in the technical sense.

> |  Thus (3) could be written more simply as:
> |
> | (3') [x in L if p(x)]
>
> (x in L) is a legal expression already.  (x in L) if p(x) looks  
> like the
> beginning of (x in L) if p(x) else 'blah' .  The whole thing looks  
> like a
> list literal with an incompletely specified one element.

I'm not sure I understand. I agree that

	x if (y in L if p(y)) else z

doesn't look great. Neither does

	x if (y for y in L if p(y)) else z

Well, the 'for' in the second one is a bit of a hint, I suppose.  I  
wouldn't write either anyway.  Most of the time when I write a list  
comprehension / generator expression it is to bind it to a name.

> | This is consistent with common mathematical notation:
>
> 'Common mathematical notation' is not codified and varies from  
> writer to
> writer and even within the work of one writer.  Humans make do and  
> make
> guesses, but parser programs are less flexible.

Yet all modern mathematicians will understand the three forms without  
any hesitation and 'making guesses' (consciously at least).

> | * { f(x) | x \in L } means the set of all f(x) for x in L
> | * { f(x) | x \in L, p(x) } means the set of all f(x) for x in L
> | satisfying predicate p.
> | * { x \in L | p(x) } means the set of all x in L satisfying  
> predicate p.
>
> I personally do not like the inconsistency of the last form, which  
> flips
> '\in L' over the bar just because f(x) is the identify function.

In fact the last form is 'the consistent one', as the first two  
should really be written as:

* { y \in M | \exists x \in L, y=f(x) }
* { y \in M | \exists x \in L, p(x) and y=f(x) }

(M being the codomain of f)

;oP

Anyway, while I still like the idea, you've made me think about it as  
some sort of 'useless tinkering', which is probably is.

-- 
Arnaud





More information about the Python-ideas mailing list