detaching comprehensions

Peter Otten __peter__ at web.de
Fri Sep 8 17:03:47 EDT 2017


Stefan Ram wrote:

>   Maybe you all know this, but to me this is something new.
>   I learnt it by trial and error in the Python 3.6.0 console.
> 
>   Most will know list comprehensions:
> 
> |>>> [ i for i in range( 3, 5 )]
> |[3, 4]
> 
>   I found out that the comprehension can be detached from the list:
> 
> |>>> k =( i for i in range( 3, 5 ))
> 
>   but one must use an extra pair of parentheses around it in the
>   assignment.

That is called "generator expression". When it does not modify the values 
one usually creates the iterator with k = iter(range(3, 5)).

>   Now I can insert the "generator" »k« into a function call,
>   but a spread operator should cannot be used there.
> 
> |>>> sum( k )
> |7
> 
>   »sum« expects exactly two arguments, and this is what »k«
>   provides.

No. sum() requires one iterable and accepts an optional start value. You are 
passing the iterable only, as may be verified with

 >>> k = (x for x in [["a"], ["b"]])
>>> sum(k)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'list'

versus

>>> k = (x for x in [["a"], ["b"]])
>>> sum(k, [])
['a', 'b']

As with iterators in general once they are exhausted they stay exhausted:

>>> k = (i for i in range(3, 5))
>>> sum(k)
7
>>> sum(k)
0

(you can but shouldn't make your own that doesn't follow that convention)

>   But to insert it again into the place where it was "taken
>   from", a spread operator is required!
> 
> |>>> k =( i for i in range( 3, 5 ))
> |>>> [ *k ]
> |[3, 4]

I have not seen that, I think. The common way is probably

>>> list("foo")
['f', 'o', 'o']

rather than

>>> [*"foo"]
['f', 'o', 'o']

and

>>> tuple("bar")
('b', 'a', 'r')

rather than 

>>> *"bar",
('b', 'a', 'r')

As demonstrated this works with arbitrary iterables, not just generator 
expressions.




More information about the Python-list mailing list