[Python-ideas] Fwd: Fwd: unpacking generalisations for list comprehension
Steven D'Aprano
steve at pearwood.info
Thu Oct 13 21:04:07 EDT 2016
On Thu, Oct 13, 2016 at 08:15:36PM +0200, Martti Kühne wrote:
> Can I fix my name, though?
I don't understand what you mean. Your email address says your name is
Martti Kühne. Is that incorrect?
[...]
> I meant that statement in context of the examples which were brought up:
> the occurrence of a list comprehension inside an array have the
> following effect:
>
> 1) [ ..., [expr for t in iterable] ]
>
> is equivalent to:
>
> def expr_long(iterable, result):
> result.append(iterable)
> return result
>
> expr_long(iterable, [ ..., ])
The good thing about this example is that it is actual runnable code
that we can run to see if they are equivalent. They are not equivalent.
py> def expr_long(iterable, result):
... result.append(iterable)
... return result
...
py> iterable = (100, 200, 300)
py> a = [..., [2*x for x in iterable]]
py> b = expr_long(iterable, [...])
py> a == b
False
py> print(a, b)
[Ellipsis, [200, 400, 600]] [Ellipsis, (100, 200, 300)]
For this to work, you have to evaluate the list comprehension first,
then pass the resulting list to be appended to the result.
I don't think this is very insightful. All you have demonstrated is that
a list display [a, b, c, ...] is equivalent to:
result = []
for x in [a, b, c, ...]:
result.append(x)
except that you have written it in a slightly functional form.
> so, if you make the case for pep448, you might arrive at the following:
>
> 2) [ ..., *[expr for expr in iterable] ]
That syntax already works (in Python 3.5):
py> [1, 2, 3, *[x+1 for x in (100, 200, 300)], 4, 5]
[1, 2, 3, 101, 201, 301, 4, 5]
> which would be, if I'm typing it correctly, equivalent to, what
> resembles an external collection:
>
> def expr_star(list_comp, result):
> result.extend(list(list_comp))
> return result
>
> expr_star(iterable, [ ..., ])
>
> Having this in mind, the step to making:
>
> [ ..., [*expr for expr in iterable], ]
>
> from:
>
> def expr_insidestar(iterable, result):
> for expr in iterable:
> result.extend(expr)
> return result
>
> does not appear particularly far-fetched, at least not to me and a few
> people on this list.
But you don't have [..., list_comp, ] you just have the list comp.
You are saying:
(1) List displays [a, b, c, d, ...] are like this;
(2) we can sensibly extend that to the case [a, b, *c, d, ...]
I agree with (1) and (2). But then you have a leap:
(3) therefore [*t for t in iterable] should mean this.
There's a huge leap between the two.
To even begin to make sense of this, you have to unroll the list
comprehension into a list display. But that's not very helpful:
[expr for t in iterable]
Would you rather see that explained as:
[expr, expr, expr, expr, ...]
or as this?
result = []
for t in iterable:
result.append(expr)
The second form, the standard, documented explanation for
comprehensions, also applies easily to more complex examples:
[expr for t in iter1 for u in iter2 for v in iter3 if condition]
result = []
for t in iter1:
for u in iter2:
for v in iter3:
if condition:
result.append(expr)
--
Steve
More information about the Python-ideas
mailing list