My objective is to get my head around the concept of sending data to a Python generator. Below is my code snippet and the unexpected output:
def spam():
while True:
received = yield
print("Message received from generator function:", received)
yield received
if __name__ == "__main__":
s = spam()
print(s)
next(s)
names = ["Bob", "Nancy", "Daniela", "Martin"]
for name in names:
print(s.send(name))
Output :
7tvmb228:Own subhayan.bhattachary$ python test_generators.py
<generator object spam at 0x10873aa20>
Message received from generator function: Bob
Bob
None
Message received from generator function: Daniela
Daniela
None
Can someone please point me out where is the None values coming from and how to solve that . My assumption is somehow that values do not get passed to the function. But why is that the case. Where am i going wrong .
Thanks for any answers in advance.
The None
values are coming from received = yield
, which essentially means you are yielding None
value. You need to have only one yield
in your spam()
function:
def spam():
received = None
while True:
received = yield received
print("Message received from generator function:", received)
if __name__ == "__main__":
s = spam()
print(s)
next(s)
names = ["Bob", "Nancy", "Daniela", "Martin"]
for name in names:
print(s.send(name))
Prints:
<generator object spam at 0x7f1518c8f9e8>
Message received from generator function: Bob
Bob
Message received from generator function: Nancy
Nancy
Message received from generator function: Daniela
Daniela
Message received from generator function: Martin
Martin
According to the docs:
Because generator-iterators begin execution at the top of the generator's function body, there is no yield expression to receive a value when the generator has just been created. Therefore, calling send() with a non-None argument is prohibited when the generator iterator has just started, and a TypeError is raised if this occurs (presumably due to a logic error of some kind). Thus, before you can communicate with a coroutine you must first call next() or send(None) to advance its execution to the first yield expression.
So you may change your code like this:
def spam():
while True:
received = yield
print("Message received from generator function:", received)
yield received
if __name__ == "__main__":
s = spam()
print(s)
names = ["Bob", "Nancy", "Daniela", "Martin"]
for name in names:
next(s)
print(s.send(name))
The documentation states:
Values are sent into a generator by calling its
send(value)
method. This method resumes the generator's code and theyield
expression returns the specified value. If the regular__next__()
method is called, theyield
returnsNone
.
Solution
Put an additional next(s)
after each send to 'flush' the None
results.
def spam():
while True:
received = yield
print("Message received from generator function:", received)
yield received
if __name__ == "__main__":
s = spam()
print(s)
next(s)
names = ["Bob", "Nancy", "Daniela", "Martin"]
for name in names:
print(s.send(name))
next(s)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.