Sahand
Sahand

Reputation: 8380

Python: Understanding yield assignment in generator

Here's an infinite looper which I've added row number prints to to facilitate tracing of the program execution.

def infinite_looper(objects):
    count = 0
    print("row 35")
    while True:
        print("row 37")
        if count >= len(objects):
            count = 0
        print("Row 40")
        message = yield objects[count]
        print("row 42")
        print("The message is "+str(message))
        print("row 44")
        if message != None:
            count = 0 if message < 0 else message
            print("row 47, count = "+str(count))
        else:
            count += 1
            print("row 50")
        print("Row 51")

x = infinite_looper("abcdefghijkl")

print("executing next 1st time")
print(next(x))

print("executing next 2nd time")
print(next(x))

print("executing send 1st time")
print(x.send(10))

The output is:

executing next 1st time
row 35
row 37
Row 40
a
executing next 2nd time
row 42
The message is None
row 44
row 50
Row 51
row 37
Row 40
b
executing send 1st time
row 42
The message is 10
row 44
row 47, count = 10
Row 51
row 37
Row 40
k

What I don't understand is what happens before "executing send 1st time" is printed. b has just been output by the program, presumably through the message = yield objects[count] row in infinite_looper. But then, the value of message is changed to 10 from None even though message = yield objects[count] has already been executed! My only theory is that the yield keyword works in such a way that the execution "stays" on its row after it's been executed, and a send statement to the looper can make the same row (in this case message = yield objects[count]) execute again. Otherwise, we would have:

executing send 1st time
row 42
The message is **None**

Is this a correct theory? More details on how this works?

Upvotes: 0

Views: 857

Answers (1)

user2357112
user2357112

Reputation: 282138

But then, the value of message is changed to 10 from None even though message = yield objects[count] has already been executed!

No. A value has been yielded, but until the send call, the value of the yield objects[count] expression has not been determined or assigned to message. The generator's execution is suspended midway through execution of the line. (Remember that the value of a yield expression is not the same as the value it yields.)

The x.send(10) call causes the yield expression to take value 10, and that value is what is assigned to message.

Upvotes: 5

Related Questions