Python language basics 64: a basic example of yield generators

Introduction

In the previous post we looked at the continue keyword in Python. We saw how it helped us stop the execution of a loop in case the current value of the iteration wasn’t to be handled in the same way as others.

In this post we’ll look at something completely different: the somewhat odd language construct of yielding a value.

The English word ‘yield‘ means approximately ‘produce’ or ‘give way’. A good investment can yield a high return. A fertile field can yield a lot of corn.

Yielding in Python

The yield keyword in Python is similar in usage. It is used in conjunction with loops that are lazily evaluated, where lazy means ‘on demand’ so that no memory is occupied unless the function is evaluated by the caller. Also, the function that yields a value – called a generator function – “remembers” the state from the previous execution. This all may sound mysterious. The usage of the yield keyword is definitely confusing at first I think.

C# has also a yield keyword and it works similar to how it does in Python. I’m not aware of any equivalent in Java.

You can think of generator functions as collections, or iterables. Iterables are objects that can be iterated, just like collections, in a for-each loop. A function which has the yield keyword automatically becomes a generator function that can be called in a for-each loop. Generator functions cannot be called and executed like “normal” functions.

Here’s a normal integer list with an iterator:

integers = [1, 2, 3, 4]
for i in integers:
    print('Printing ', i)

Here’s the output:

Printing 1
Printing 2
Printing 3
Printing 4

Here’s the generator function equivalent of the above code:

def integer_yielder():
    yield 1
    yield 2
    yield 3
    yield 4

integers = integer_yielder()
for i in integers:
    print('Printing ', i)

We have a generator function with 4 yield statements. You can think of yield statements really as yield return statements. The above generator function has 4 yield return statements. It will return 1 in the first iteration and “remember” that it has already returned 1. In the next iteration it returns 2 and so on until there are no more elements to be “yielded”.

Notice how we assign integer_yielder to a variable just like we assigned an integer list to it previously. The key difference is that the integer list was loaded into memory at the moment of the variable assignment. Generator functions on the other hand are evaluated lazily in a just-in-time manner, meaning that the integers 1, 2, 3 and 4 yielded by the function are not loaded into memory. First only ‘1’ is loaded when the iteration starts, and then 2, 3 and finally 4.

This second version has the exact same printout as the first.

In the next post we’ll see how yield generators can keep the state of their variables from one iteration to another.

Read all Python-related posts on this blog here.

Advertisement

About Andras Nemes
I'm a .NET/Java developer living and working in Stockholm, Sweden.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Elliot Balynn's Blog

A directory of wonderful thoughts

Software Engineering

Web development

Disparate Opinions

Various tidbits

chsakell's Blog

WEB APPLICATION DEVELOPMENT TUTORIALS WITH OPEN-SOURCE PROJECTS

Once Upon a Camayoc

Bite-size insight on Cyber Security for the not too technical.

%d bloggers like this: