11

According to the Python documentation the yield keyword can take an "expression_list", but it is optional:

yield_expression ::=  "yield" [expression_list]

I can find no examples of such usage, either in the Python docs, in any of the answers to What does the yield keyword do in Python, nor from generally reading around the web.

If yield is used without an expression_list then I guess that the resulting method cannot be useful as a generator, so are there other scenarios where a plain yield might be useful?

1

2 Answers 2

10

Although they're almost always used as simple generators, yield enables fully-fledged coroutines.

Besides being used to send values out of a generator / co-routine, yield can also receive values, with the effect of coordinating the execution different co-routines. Thus, you don't need expression_list if you only want to coordinate or receive values.

Here's a simple example:

def infini_printer():
    while True:
        received = yield # get the received value into a variable
        print(received)

printer = infini_printer()
printer.next()              # returns None, since we didn't specify any expression after yield
printer.send("foo")         # prints "foo"
4

It works more like how a return with no arguments simply returns None.

>>> def foobar():
...    for i in range(10):
...        yield
>>>
>>> for token in foobar():
...    print(token)
None
None
None
None
None
None
None
None
None
None

Where this is going to be more common is when you are writing coroutines where there is important work you are doing in a function, and the yield point is simply the 'pause' point -- waiting for someone or something to call next or send but you may not have anything of concern to return.

>>> def do_important_work():
...
...    do_it = True
...    state = 0
...    while do_it:
...        print(state)
...        state += 1
...        # do some more important work here ...
...        do_it = yield
...
>>> worker = do_important_work()
... 
>>> worker.next()
>>> worker.send(True)
>>> worker.send(True)
>>> worker.send(True)
0
1
2
3

I think yield was simply designed so you were not forced to return a value, just like how return is designed.

Not the answer you're looking for? Browse other questions tagged or ask your own question.