0

I wrote a very simple generator function:

def prefixes(xs):
    prefix = []
    for x in xs:
        prefix.append(x)
        yield prefix

I expected the output to be:

>>> list(prefixes([1, 2, 3]))
[[1], [1, 2], [1, 2, 3]]

But I got:

>>> list(prefixes([1, 2, 3]))
[[1, 2, 3], [1, 2, 3], [1, 2, 3]]

That is very weird. How does the first iteration yield all the list? current should only contain the first item. Why is the output what it is and not what I expect?


P.S. Searching for "python list.append in generators" in Google did not give relevant results.

Caridorc
  • 6,222
  • 2
  • 31
  • 46
  • You need to `yield prefix[:]` – Padraic Cunningham Sep 01 '16 at 11:09
  • @PadraicCunningham Yes, I knew that, but I was interested in what Markjin said: "You are reusing the same list object. Your generator returns the one object over and over again, manipulating it as it goes, but any other references to it see those same changes:" Another way of fixing the function is `yield prefix[:]`. I think this way of adding items one by one is more efficient and most notably works for iterables too. – Caridorc Sep 01 '16 at 11:12
  • 2
    Note: This has nothing to do with generators, this is standard Python behavior for lists. It's the same as doing `x = [1]; my_list = []` and then `my_list.append(x)` which results in `[[1]]`. Now if you do `x.append(2); my_list.append(x)` then `my_list` will result in `[[1, 2], [1, 2]]` – juanpa.arrivillaga Sep 01 '16 at 11:12
  • Almost exact duplicate: http://stackoverflow.com/q/32514807/2301450 Another similar question: http://stackoverflow.com/q/7503639/2301450 – vaultah Sep 01 '16 at 11:12
  • Sorry I actually meant `yield prefix[:]`, there is only one list which is created when you call the function, once you hit the loop and you start yielding you are just yielding a reference to the same object. – Padraic Cunningham Sep 01 '16 at 11:14
  • Perhaps doing the following in the interpreter shell will clear up things: `it = iter(prefixes([1,2,3]))` Now try `next(it)`, which should give you `[1]`. Then one more time `next(it)` will give `[1,2]` and finally, one more `next(it)` will give you `[1, 2, 3]` ` – juanpa.arrivillaga Sep 01 '16 at 11:17
  • @juanpa.arrivillaga `iter` is not needed as a generator is already iterable. – Caridorc Sep 01 '16 at 11:44
  • @Caridorc yes, my mistake, but the point still stands. – juanpa.arrivillaga Sep 01 '16 at 11:49
  • @juanpa.arrivillaga [this example](http://codepaste.net/a3v723) may be interesting for future visitors – Caridorc Sep 01 '16 at 11:52
  • @Caridorc I am here, but the link is broken( – Jane Sep 25 '19 at 10:05
  • @Jane sorry so much time passed, I do not remember it neither... – Caridorc Sep 29 '19 at 14:47

0 Answers0