I need a 2D loop of which the first loop uses an iterator and the second uses a generator, but this simple function failed to work, can anyone help to check?
Since you've asked for clarification, I'll say a bit more; but really Ignacio's answer sums it up pretty well: you can only iterate over a generator once. The code in your example tries to iterate over it three times, once for each value in a
.
To see what I mean, consider this simplistic example:
>>> def mygen(x):
... i = 0
... while i < x:
... yield i
... i += 1
...
>>> mg = mygen(4)
>>> list(mg)
[0, 1, 2, 3]
>>> list(mg)
[]
When mygen
is called, it creates an object which can be iterated over exactly once. When you try to iterate over it again, you get an empty iterable.
This means you have to call mygen
anew, every time you want to iterate over it`. So in other words (using a rather verbose style)...
>>> def make_n_lists(gen, gen_args, n):
... list_of_lists = []
... for _ in range(n):
... list_of_lists.append(list(gen(*gen_args)))
... return list_of_lists
...
>>> make_n_lists(mygen, (3,), 3)
[[0, 1, 2], [0, 1, 2], [0, 1, 2]]
If you wanted to bind your arguments to your generator and pass that as an argumentless function, you could do this (using a more terse style):
>>> def make_n_lists(gen_func, n):
... return [list(gen_func()) for _ in range(n)]
...
>>> make_n_lists(lambda: mygen(3), 3)
[[0, 1, 2], [0, 1, 2], [0, 1, 2]]
The lambda
just defines an anonymous function; the above is identical to this:
>>> def call_mygen_with_3():
... return mygen(3)
...
>>> make_n_lists(call_mygen_with_3, 3)
[[0, 1, 2], [0, 1, 2], [0, 1, 2]]
The first iteration over b
consumes the generator.