0

This question is with reference to this [Stackoverflow][1] post about the keyword "yield".

I understand that if there is a "yield" statement in the function, the function is called a generator function. The generator function gives a generator object to the function call, unlike a function with a return statement.

def generatorFunc():

    global numList
    numList = range(8)

    
    for i in numList:
        
        
        print(f"id of {i} is {id(i)}")
        
        yield i*i
    

mygenerator = generatorFunc()
print(mygenerator)

In the code given above, the output was as follows:

<generator object generatorFunc at 0x000001E9692A0BA0>

I understand that when the function was called, the generator object was created without going through the body of the function.

Running the following code generated the iterable, and the function body was executed.

def generatorFunc():
    
    global numList
    numList = range(8)

    
    for i in numList:
        
        
        print(f"id of {i} is {id(i)}")
        
        yield i*i
    

mygenerator = generatorFunc()
print(mygenerator)

list2 = ([i*i for i in mygenerator])
print(list2)

Output

<generator object generatorFunc at 0x000001E9692A0F90>
id of 0 is 140733860812528
id of 1 is 140733860812560
id of 2 is 140733860812592
id of 3 is 140733860812624
id of 4 is 140733860812656
id of 5 is 140733860812688
id of 6 is 140733860812720
id of 7 is 140733860812752
[0, 1, 16, 81, 256, 625, 1296, 2401]

Next, when I ran the following code, the output came off as a bit strange. I could not give myself a satisfactory explanation.

def generatorFunc():
    
    global numList
    numList = range(8)

    
    for i in numList:
        
        
        print(f"id of {i} is {id(i)}")
        
        yield i*i
    

mygenerator = generatorFunc()
print(mygenerator)


for i in mygenerator:
    
    print(f"value of i is {i}")
    print(f"the list is {list(mygenerator)}")

list2 = ([i*i for i in mygenerator])

print(list2)

output

<generator object generatorFunc at 0x000001E9692A0CF0>
id of 0 is 140733860812528
value of i is 0
id of 1 is 140733860812560
id of 2 is 140733860812592
id of 3 is 140733860812624
id of 4 is 140733860812656
id of 5 is 140733860812688
id of 6 is 140733860812720
id of 7 is 140733860812752
the list is [1, 4, 9, 16, 25, 36, 49]
[]

I didn't understand why "print(f"value of i is {i}")" was executed only once, and print(f"the list is {list(mygenerator)}") was printed in the last? Does it mean that, once the "for" uses the "generator object", the function is executed from top to bottom, and subsequently "generator object" becomes empty? Can someone help me understand the last code in my question and why the output is so? [1]: What does the "yield" keyword do in Python?

1 Answers1

2

The issue is with the following lines of code:

for i in mygenerator:
    
    print(f"value of i is {i}")
    print(f"the list is {list(mygenerator)}")

A generator does not store values in memory. When you convert the generator to a list, the generator is exhausted; there are no longer any values. Thus, the loop stops after one run.

Furthermore, only when the generator is iterated over is the body of the generator executed, hence the order of the output given.

  • thanks for your answer. You are saying that as and when the generator object was converted to a list object, the former got exhausted, and there was nothing to loop over. When the for-loop uses the generator object, the function body was executed, and later the first print() within the for-loop works. When the generator object was converted to a list object, the generator got empty. If so, how can list(generator) get printed at last? – Vijith Kumar V Aug 16 '23 at 11:23
  • Look at the line `print(f"the list is {list(mygenerator}")`. When you first convert the generator to a list, the generator still has values, so a list of values is returned. Only after the conversion does the generator lose its values. This is why it is able to print the list of values in the generator during the print but then exists the loop. Let me know if you're still confused about how it is working. – Dubious Denise Aug 16 '23 at 11:30
  • When you say this, "When you first convert the generator to a list, the generator still has values", the `print(f"the list is {list(mygenerator}")` should print the list in the beginning, shouldn't it? I mean, the last output has 12 lines, and my confusion is why the list wasn't printed at line 4, but at line 11. I am sorry, I am not following the logic quite well. – Vijith Kumar V Aug 16 '23 at 11:55
  • 2
    The value of `list(mygenerator)` isn't available until the generator has yielded every value. In order to do that, the for-loop inside the generator has to iterate 7 times. Therefore you see 7 lines of `id of...` printed before `list(mygenerator)` is returned for printing. – slothrop Aug 16 '23 at 12:02
  • 1
    slothrop, now this comment did really make sense. Now, the concept is clear. – Vijith Kumar V Aug 16 '23 at 12:47