Understanding execution sequence with generators in python

Viewed 38

I have simple program that I am using to understand how generators/yeild works.

def learn_yield(numbers):
    for i in numbers:
        yield (i*i)

numbers = [5]

sq = learn_yield(numbers)

numbers.append(6)

for i in sq:
    print (i)

Here's where my understanding is unclear:

The append method is called after the call to the learn_yield function. I would have expected the output of print(i) as 25 and not

25 36

How exactly did the number 6 get sent to the function?

If I move numbers.append(6) to after the for loop, then I get the behavior I think should happen in the first place. Does this mean that the call to the function is made again when the loop is iterating?

System - PC, Windows 10 Python - 3.7 Sublime Text

1 Answers

What happens is that learn_yield retains a reference to numbers. When you append to numbers, all code that has a reference to it will see the change.

Put another way, numbers in the function and numbers in the main code are the same object.

If you want to sever that link, you could make learn_yield iterate over a copy:

def learn_yield(numbers):
    for i in numbers[:]:   # [:] makes a copy
        yield (i*i)

For a detailed discussion of how arguments are passed in Python, see How do I pass a variable by reference?

Related