Search code examples
pythongeneratorsend

Python generator send() strange behaviour


While I try to understand the mechanism of generator's send() method, I encountered a strange behaviour in my example. (VS Code Python 3.10)

def MultipleOfThree():
    num  = 1
    while True:
        if num % 3 == 0:
           yield num
        num += 1

#test
iter = MultipleOfThree()

for m3 in iter:    
    print(m3)

This code is working as expected and prints

>>> 3,6,9,12,15,18,21.....

When I add the send() statement in for loop, and arrange the MultipleOfThree() func like below

def MultipleOfThree():
    num  = 1

    while True:
        if num % 3 == 0:
            i = yield num   
            if i is not None:
                num = i
        num += 1

#test
iter = MultipleOfThree()

for m3 in iter:    
    print(m3)
    iter.send(m3) #for simplicity send the m3 itself

it prints

>>> 3,9,15,21,27

I couldn't understand the mechanism of send() here, why escapes the for loop. I study the subject from this page How to Use Generators and yield in Python.


Solution

  • First initialize the generator:

    iter = MultipleOfThree()
    

    Get the first value:

    m3= next(iter)
    

    Then continue in a while loop:

    while True:
        print(m3)
        m3 = iter.send(m3)
    

    You wish to get the first value using next(iter) or iter.send(None) in order to reach the first multiple of three, without any input.

    Then, you want to send back the input and continue from there using iter.send(m3).

    Overall code:

    def MultipleOfThree():
        num  = 1
        while True:
            if num % 3 == 0:
                i = yield num   
                if i is not None:
                    num = i
            num += 1
    
    iter = MultipleOfThree()
    m3= next(iter)
    while True:
        print(m3)
        m3 = iter.send(m3)