[docs] sum( ) in generator bugged

Zachary Ware zachary.ware+pydocs at gmail.com
Tue Dec 8 12:56:17 EST 2015


Hi Anselm,

On Fri, Nov 27, 2015 at 6:51 AM, Anselm Kiefner
<python at anselm.kiefner.de> wrote:
> Hi,
>
> I just found this bug:
>
> Python 3.4.3+ (default, Oct 14 2015, 16:03:50)
> [GCC 5.2.1 20151010] on linux
>
>>>> L = [1,2,3]
>>>> L_g = (x for x in L)
>>>> a = [x*sum(L) for x in L]
>>>> b = (x*sum(L_g) for x in L_g)
>>>> print(a, list(b))
> [6, 12, 18] [5]
>
> whether b is a generator or not doesn't make a difference, it seems to
> be a problem with sum() operating on L_g while L_g is consumed.
> I stumbled over the problem first in ipython notebook running python
> kernel 3.5.0, but couldn't find anything about it in the bugtracker.

First off, this is not the place to report bugs; that should be done
on the bug tracker or reported to python-list at python.org (and someone
there will either explain why it's not a bug, or make sure it's
reported properly).  This list is for discussion about the
documentation of Python rather than its inner workings (except where
that affects the documentation :)).

However, this is not a bug in Python, but rather in your expectations.
In `b = (x*sum(L_g) for x in L_g)` you're trying to loop over the same
iterator multiple times, which actually works out such that `for x in
L_g` consumes the first value (1), then `x*sum(L_g)` consumes the rest
(2, 3), so `x*sum(L_g)` expands to `1*(2 + 3)`, which gives 5.  Next
time around the loop, L_g is already exhausted, so the for loop ends.
If you want to iterate over the same values multiple times, you need
either a concrete list of the values, or to calculate the values
separately on every iteration.  Either of the following will work the
way you expected in the first place; performance will depend on your
real use case; if you're concerned about memory use but have cycles to
spare, go for the first; if you have memory but want shorter runtime,
go for the second.

First:
   >>> L = [1,2,3]
   >>> def gen(lst):
   ...     for x in lst:
   ...         yield x
   ...
   >>> b = (x * sum(gen(L)) for x in gen(L))
   >>> list(b)
   [6, 12, 18]

Second:
   >>> g_L = list(x for x in L)
   >>> b2 = (x*sum(g_L) for x in g_L)
   >>> list(b2)
   [6, 12, 18]

Hope this helps,
-- 
Zach


More information about the docs mailing list