开发者

python3: list() from generator: strange behaviour when yielding item-changed lists

I have a generator defined like this:

def gen():
    r = [0]
    yield r
    r[0] = 1
    yield r
    r[0] = 2
    yield r

it will yield three lists of one element going from 0 to 2:

>>> a = gen()
>>> next(a)
[0]
>>> next(a)
[1]
>>> next开发者_StackOverflow中文版(a)
[2]
>>> next(a)
Traceback (most recent call last):
  File "<pyshell#313>", line 1, in <module>
    next(a)
StopIteration

Now, when I go to make a list from the generator, I got this:

>>> list(gen())
[[2], [2], [2]]

That is, it seems to yield each time the very last computed value.

Is this a python bug or am I missing something?


It's not a bug, it does exactly what you told it to do. You're yielding the very same object several times, so you get several references to that object. The only reason you don't see three [2]s in your first snippet is that Python won't go back in time and change previous output to match when objects are mutated. Try storing the values you get when calling next explicitly in variables and check them at the end - you'll get the same result.

Such an iterator is only useful if no yielded value is used after the iterator is advanced another time. Therefore I'd generally avoid it, as it produces unexpected results when trying to pre-compute some or all results (this also means it breaks various useful tricks such as itertools.tee and iterable unpacking).


You want:

def gen():
    for i in (0,1,2):
        yield [i]

That will yield three lists, not one list three times.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜