def generator(dct):
for i in range(3):
dct['a'] = i
yield dct
g = generator({'a': None})
next(g) # -> {'a': 0}
next(g) # -> {'a': 1}
next(g) # -> {'a': 2}
g = generator({'a': None})
list(g) # -> [{'a': 2}, {'a': 2}, {'a': 2}]
next
итератор генератора, как я и ожидал. Однако list
неожиданно повторяется. Я думаю, что он должен возвратить [{'a': 0}, {'a': 1}, {'a': 2}]
так как next
итерации без проблем.
Интересно, в чем разница.
(моя среда: python 3.6.5, conda 4.5.4, Windows)
generator()
генератора всегда дает один и тот же объект dict
, только с изменениями, внесенными в него между вызовами. Если бы вы, скажем, изменили первый next(g)
на x = next(g)
а затем проверили x
до и после вызова next(g)
снова, вы увидите значение изменения x
разных вызовов, потому что generator()
всегда изменяет и дает один и тот же объект dict
.
Они одинаково перебирают итератор, но вы проверяете их в разных точках. Поскольку dict
изменчивы, и вы всегда yield
один и тот же dict
, вы должны ожидать все, что вы уступаете быть идентичными. В вашем первом примере вы смотрите на dict
поскольку он меняется. Вместо этого
g = generator({'a': None})
a = next(g)
b = next(g)
c = next(g)
print(a, b, c)
# {'a': 2} {'a': 2} {'a': 2}
Вы просматриваете промежуточные результаты печати. Вы изменяете один словарь и обмениваетесь ссылками на него. Вы можете видеть промежуточные шаги, но это не значит, что результат отличается.
Сохраните ссылку на объект, возвращенный из next()
и все они будут одинаковыми:
g = generator({'a': None})
first = next(g)
second = next(g)
third = next(g)
print(first, second, third) # -> {'a': 2} {'a': 2} {'a': 2}
first
, second
и third
- все ссылки на один и тот же объект:
>>> first is second and second is third
True
Вы увидели бы то же самое, если вы сделали это в регулярном for
цикла:
>>> results = []
>>> d = {'a': None}
>>> for i in range(3):
... d['a'] = i
... print(d)
... results.append(d)
...
{'a': 0}
{'a': 1}
{'a': 2}
>>> print(results)
[{'a': 2}, {'a': 2}, {'a': 2}]
>>> all(d is elem for elem in results) # all references in results are the same object
True
Цикл печатает объект словаря при изменении каждого шага. Список results
содержит 3 ссылки на один и тот же объект, и каждый показывает одно и то же состояние после печати в конце.