can't generate iterator from list
Peter Otten
__peter__ at web.de
Sat Sep 10 03:05:43 EDT 2011
Dr. Phillip M. Feldman wrote:
>
> It is supposed to be possible to generate a list representation of any
> iterator that produces a sequence of finite length, but this doesn't
> always work. Here's a case where it does work:
>
> Input:
>
> from itertools import combinations
> list(combinations(range(4),2))
>
> Output:
>
> [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]
>
> When I define my own classes that produce iterators, conversion to a list
> works for some of these classes but not for others. Here's a case where it
> doesn't work:
>
> In: list(balls_in_numbered_boxes(2, [3,3,3]))
>
> Out:
>
> [array([0, 0, 1]),
> array([0, 0, 1]),
> array([0, 0, 1]),
> array([0, 0, 1]),
> array([0, 0, 1])]
[snip code where excessive commenting does more bad than good]
The problem is that you return the same mutable object on every next() call.
Here's a simplified example:
>>> def g(items):
... x = [None]
... for item in items:
... x[0] = item
... yield x
...
>>> list(g("abc"))
[['c'], ['c'], ['c']]
When you invoke it using next() you are fooled into thinking that it works
as desired:
>>> it = g("abc")
>>> a = next(it)
>>> a
['a']
>>> b = next(it)
>>> b
['b']
but only until you look back at the previous item:
>>> a
['b']
Once you understand what is going on the fix is easy -- don't reuse the
mutable object:
>>> def g(items):
... for item in items:
... yield [item]
...
>>> list(g("abc"))
[['a'], ['b'], ['c']]
More information about the Python-list
mailing list