user5323608
user5323608

Reputation: 33

Python appending to and yielding a list

What is going on here? Why does list(f(seq)) return something other than a list of the elements yielded by f?

>>> def f(seq):
...   a = []
...   for i in seq:
...     yield a
...     a.append(i)
...
>>> f([1,2,3])
<generator object f at 0x1066c7aa0>
>>> b = f([1,2,3])
>>> b.next()
[]
>>> b.next()
[1]
>>> b.next()
[1, 2]
>>> b.next()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>> list(f([1,2,3]))
[[1, 2, 3], [1, 2, 3], [1, 2, 3]]

Upvotes: 3

Views: 1510

Answers (2)

AChampion
AChampion

Reputation: 30268

You are yielding the list you created in the generator and not a copy of the list. Lists are mutable so any changes to that list are reflected in all references to that list.
Consider this:

>>> a = [[]]*4      # Create a list of 4 references to the same list
>>> a[0].append(1)  # Add 1 the first reference
>>> a
[[1], [1], [1], [1]]

Upvotes: 1

metatoaster
metatoaster

Reputation: 18908

You have yielded the entire reference to the list a inside the function. When list(f([1,2,3])) is called the result simply is [a, a, a], and the final form of a is [1, 2, 3].

This is no different if you had saved all the results from the f.next() calls.

>>> v1 = b.next()
>>> v2 = b.next()
>>> v1
[1]
>>> v2
[1]
>>> v3 = b.next()
>>> v4 = b.next()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>> v1
[1, 2, 3]

Again, this is correct because a is yielded and is the same reference to the same internal list inside the function f.

Upvotes: 3

Related Questions