3

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

Hector M
  • 47
  • 4

1 Answers1

2

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?

NPE
  • 486,780
  • 108
  • 951
  • 1,012
  • Thanks. Can you also share as to why this does not apply when we move the numbers.append to after the for loop. Why does that break the reference to numbers? – Hector M Oct 12 '19 at 11:15
  • @HectorM: It does not. What happens in that case is that the number is only appended _after `learn_yield` has finished iterating_ and so it never sees the 6. – NPE Oct 12 '19 at 11:19