list comprehensions whats happening here
Steve Holden
sholden at holdenweb.com
Fri Apr 13 15:19:21 EDT 2001
"Carlos Ribeiro" <cribeiro at mail.inet.com.br> wrote ...
> At 07:06 13/04/01 -0700, Emile van Sebille wrote:
> >I suspect the answer lies somewhere in the comma converting the parts of
the
> >list comprehension into a list itself, much as the comma is used in
normal
> >iteration idiom:
> >
> >for i in 1,2
>
> As other have pointed out, your're right, that does explain why it works
> that way. But...
>
> >>>[[i,j] [1,2,3], for j in 'abc',]
> Traceback ( File "<interactive input>", line 1
> [[i,j] [1,2,3], for j in 'abc',]
>
> does not work, yet
>
Why should this work? A list comprehension substitutes one or more bound
variables into a legitimate expression to generate the list members. But
[i,j] [1,2,3]
is *not* a legitimate expression: the interpreter will complain because it
thinks you are trying to subscript the list [i,j] with a tuple 1,2,3 -- list
subscripts have to be integers.
> >>> [[i,j] for i in range(3), for j in range(3)]
> [[[0, 1, 2], 0], [[0, 1, 2], 1], [[0, 1, 2], 2]]
>
> work.
>
Indeed. Let's take this a piece at a time... start by giving j a fixed value
42.
[[i,j] for i in range(3),]
is a legitimate expression: it is equivalent to
[[i,j] for i in (range(3), )]
In other words, it produces a list of [i,j] lists, for i taking on every
value of the tuple (range(3), ) - a single-element tuple, so the result from
either of these expressions would be
[[[0, 1, 2], 42]]
This is correct: we get a single element list whose only element is the list
[i, j], where i was range(3) (the only value in the single-element tuple i
was iterating across) and j was 42.
Let's look at your expression again, using a different range for j just so
it's clearer which contributes to what:
[[i,j] for i in range(3), for j in range(6,9)]
should give you a list containing three elements, since now j takes on not
just a single value but three. Sure enough, the result is
[[[0, 1, 2], 6], [[0, 1, 2], 7], [[0, 1, 2], 8]]
This is a list of three elements, one for each value of j. Each element of
the list is a list of two elements, the first of which is the value of i
(which is to say, range(3), or [0,1,2]) followed by a value of j (which is
to say 6, then 7, then 8).
And that's why
[[i,j] for i in range(3), for j in range(3)]
evaluates to
[[[0, 1, 2], 0], [[0, 1, 2], 1], [[0, 1, 2], 2]]
It's also why
[[i,j] for i in range(3), for j in range(6,9),] # note second trailing comma
has only one value - because both i and j are iterating over single-element
tuples.
[[[0, 1, 2], [6, 7, 8]]]
> I am not advocating that something is wrong; I just want to point out that
> some funny things are happening as a side effect of the grammar and/or
> compiler. It's impossible to supply a list as part of the list
> comprehension syntax, but you can fake it by writing a comma after the for
> clause. That's just weird, and unexpected.
>
Nope, that's a tuple, not a list. Just so happened that it's a
single-element tuple, whose only member is a list. If it's any help, I agree
it's weird and unexpected, but you have to realise we're out on the edges
here.
> Question: this may turn out to be wrong, and it may be fixed in the
future;
> OTOH, it can be useful, and (in a rather obscure way) consistent with
> Python syntax. What's the take on this? Let it be, or fix it, as a
> undesirable side effect that don't belong to list comprehensions?
>
My own take is that everything is entirely consistent, and should be left
alone. There's a good reason why the list comprehension syntax doesn't have
commas in it!
Hope this helps.
regards
Steve
More information about the Python-list
mailing list