1
>>>def change(x): 
...    x.append(len(x))
...    return x
>>>a=[]
>>>b=(change(a) for i in range(3))
>>>next(b)
[0]
>>>next(b)
[0,1]
>>>next(b)
[0,1,2]
>>>next(b)
Traceback ... StopIteration
>>>a=[]
>>>b=(change(a) for i in range(3))
>>>list(b) #expecting [[0],[0,1],[0,1,2]]
[[0,1,2],[0,1,2],[0,1,2]] 

So I was just testing my understanding of generators and messing around with the command prompt and now I'm unsure if I actually understand how generators work.

Dan
  • 133
  • 6
  • 2
    Your problem is the scope. All elements in `b` refer to the same variable `a` (which is returned from the `change` function), so what you are seeing is just the final value, since all the outputs point to the same object. This has nothing to do with iterators, is a combination of _scope_ and how python handles _arguments in functions_. – EsotericVoid Aug 20 '17 at 07:24
  • 1
    Hey @Bit, so is it because when I do `list(b)` it essentially goes to `[a,a,a]` due to the function returning `a` 3 times in the for loop, and because `a` is `[0,1,2]` in the end that's why I'm seeing `[[0,1,2],[0,1,2],[0,1,2]]`? – Dan Aug 20 '17 at 07:35
  • 1
    Exactly. If you want to read more, [https://stackoverflow.com/questions/6059205/evaluating-a-list-of-python-lambda-functions-only-evaluates-the-last-list-elemen](https://stackoverflow.com/q/6059205) is a question with the same issue (it uses lambdas, but the logic is the same). – EsotericVoid Aug 20 '17 at 07:37

1 Answers1

2

The problem is that all calls to change(a) return the same object (in this case, the object is the value of a), but this object is mutable and changes its value. An example of the same problem without using generators:

a = []
b = []
for i in range(3):
   a.append(len(a))
   b.append(a)
print b

If you want to avoid it, you need to make a copy of your object (for example, make change return x[:] instead of x).

Błotosmętek
  • 12,717
  • 19
  • 29