python3: list () из генератора: странное поведение при получении списков с измененными элементами - PullRequest
1 голос
/ 21 сентября 2011

У меня есть генератор, определенный следующим образом:

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

он выдаст три списка одного элемента с 0 по 2:

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

Теперь, когда я иду, чтобы сделатьсписок из генератора, я получил это:

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

То есть, похоже, каждый раз выдает самое последнее вычисленное значение.

Это ошибка Python или я что-то упустил

Ответы [ 2 ]

2 голосов
/ 21 сентября 2011

Это не ошибка, он делает именно то, что вы сказали.Вы получаете один и тот же объект несколько раз, поэтому вы получаете несколько ссылок на этот объект.Единственная причина, по которой вы не видите три [2] с в своем первом фрагменте, состоит в том, что Python не вернется во времени и не изменит предыдущий вывод, чтобы соответствовать, когда объекты мутируют.Попробуйте сохранить значения, полученные при явном вызове next в переменных, и проверьте их в конце - вы получите тот же результат.

Такой итератор полезен, только если после итератора не используется полученное значениепродвигается в другой раз.Поэтому я бы вообще этого избегал, так как он дает неожиданные результаты при попытке предварительного вычисления некоторых или всех результатов (это также означает, что он нарушает различные полезные приемы, такие как itertools.tee и повторяемая распаковка).

0 голосов
/ 22 сентября 2011

Вы хотите:

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

Это даст три списка, а не один список три раза.

...