Simple Examples of "yield" in Python

2013-12-23 by terryoy, in tricks

The keyword “yield” in python is somewhat confusing when writing a single thread program, because it output or input a value somewhere inside the function, but you cannot tell how it does easily. So now I demonstrate two basic usages of “yield”, which you could consider as two patterns.

1. Generators

All functions using “yield” can be called generators. When using as a generator, it outputs(returns) a value somewhere inside the function, and pause at this step until it gets the next chance of execution.

The general structure of a function that uses “yield” will be like this:

def countdown(n):
    # **the settup part**
    print "Do something here"

    # **the loop part**
    while n > 0:
        yield n # return a value to the call of "next()" function, and then wait for the next loop
        n -= 1

The execution in an interactive python environment is like this:

>>> c = countdown(10)
>>> c.next()
Do something here
10
>>> c.next()
9
>>> 
...
>>> c.next()
1
>>> c.next()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  StopIteration

When the first trigger of the “next()” method, the instance “c” exectue the setup code and runs into the loop. When “n” is yield in the loop, the “next()” method gets its returning value and printed on the screen. In the next trigger of “next()”, it continues the loop so you don't see the setup part again. When the last value is yield, the while loop will end. So if “next()” method is called again, it gets a StopIteration error raised.

If you want to iterate the items generated by this generator, you don't need to catch the StopIteration, you could just use it also like iterating a list.

>>> c = countdown(3)
>>> items = [i for i in c]
Do something here
>>> items
[3, 2, 1]

2. Coroutines

The example of generators is using “yield” like an output operation, while Coroutines use it like an input operation. Check out the below code:

def accumulator(n):
    # don't forget to execute "next()" to run the setup part first
    sum = n 
    print "init value:", n
    while True:
        value = (yield) # gets a value from the method "send()"
        sum += value
        print sum # now you don't use "yield" to return value because you want 
                  # to print out the value when "send()" is called, rather than to call "next()" again

Execution:

>>> a = accumulator(0)
>>> a.next()
init value:0
>>> a.send(5)
5
>>> a.send(5)
10

In this example, you need to call “next()” first so that it could run to the first appearance of “yield”. Then, it will pause until you call “send()” method to input a number, so the loop continues and prints out the summarized value, and also pauses at “yield” in the next loop, and so on.

So when using “yield” function as coroutines, you could imagine it as a task waiting for your input, you just send the parameters to it and it will fulfill the task for you.


Tags: python