An Introduction to Python Generators and Coroutines

Before we get into the topic, let's get some definitions right first:

  1. Iterator - this is an object that can be iterated upon. An iterator object returns data, one element at a time. Some of python’s containers that are iterable include lists, tuples, strings. These have the __iter__ method defined, which when called returns an iterator object.
  2. Generator - a simple way of creating iterators defined above.
  3. Coroutine - same concept as generators but we’ll see how they differ later in the article.

To better illustrate, consider a list:[pastacode lang="python" manual="%20my_list%20%3D%20%5B1%2C%202%2C%203%2C%204%2C%205%5D%0A%20%20iter_obj%20%3D%20iter(my_list)%20%23%20calls%20__iter__%20%2C%20and%20an%20iterable%20object%20is%20returned%0A%20%20next(iter_obj)%20%23%20prints%201%0A%20%20next(iter_obj)%20%23%20prints%202%0A" message="" highlight="" provider="manual"/]And so on, till we have gotten all items from the list after which the StopIteration exception is raised. By the way, we can also call iter_obj.__next__()In order to build your own iterators, you have to implement a class with the __iter__ and __next__ methods. At times this can be very cumbersome, and that is where generators come in. Generators allow us to easily create iterators. All implementations mentioned above are not required as they are automatically handled. It’s fairly simple to create a generator in python: as easy as defining a normal function with the yield statement rather than the return statement. If you’re wondering what’s the difference between these two terms; return terminates a function while yield pauses the function while saving its state and will continue from where it left off on successive calls.As an example, we can define a simple function that is a generator for Fibonacci numbers. (Some people might argue that the sequence starts from 0 but let’s focus on the python here :[pastacode lang="python" manual="%20def%20fibonacci(limit)%3A%0A%20%20%20n2%20%3D%201%0A%20%20%20if%20limit%20%3E%3D%201%3A%0A%20%20%20%20%20%20%20yield%20n2%0A%0A%20%20%20n1%20%3D%200%0A%0A%20%20%20for%20_%20in%20range(1%2C%20limit)%3A%0A%20%20%20%20%20%20%20n%20%3D%20n1%20%2B%20n2%0A%20%20%20%20%20%20%20yield%20n%0A%20%20%20%20%20%20%20n1%2C%20n2%20%3D%20n2%2C%20n%0A%0ATo%20get%20the%20data%2C%20we%20can%20do%3A%0A%0AFib%20%3D%20fibonacci(5)%20%23%20we%20limit%20the%20number%20of%20elements%20we%20get%20to%205%0Anext(fib)%20%23%20prints%201%0Anext(fib)%20%23%20prints%201%0Anext(fib)%20%23%20prints%202%0Anext(fib)%20%23%20prints%203%0Anext(fib)%20%23%20prints%205%0Anext(fib)%20%23%20StopIteration%20exception%20is%20raised%0A" message="" highlight="" provider="manual"/]Simple, isn’t it? On to coroutines now. Please note that in this article I talk about simple coroutines rather than native coroutines.We’ve seen that generators allow us to pull data and pause execution from a function context. Coroutines allow us to push data. In this case, the yield statement basically means “Wait until you get some input data”. We also use the yield statement a bit different as we shall see in a bit. We’ll go through a very simple example which provides a good basis: Imagine we have a list of names and want to find out if some names we have in mind (we don’t know how many since they’ll be input at runtime) are in this list.[pastacode lang="python" manual="def%20check_name_exists()%3A%0A%20%20%20names%20%3D%20%5B%22Dennis%22%2C%20%22Nick%22%2C%20%22Fury%22%2C%20%22Tony%22%2C%20%22Stark%22%5D%0A%20%20%20print(%22Ready%20to%20check%20for%20names.%22)%0A%20%20%20while%20True%3A%0A%20%20%20%20%20%20%20name%20%3D%20yield%0A%20%20%20%20%20%20%20if%20name%20in%20names%3A%0A%20%20%20%20%20%20%20%20%20%20%20print(%22Found%22)%0A%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20print(%22Not%20found%22)%0A" message="" highlight="" provider="manual"/]We can now do:[pastacode lang="python" manual="coro%20%3D%20check_name_exists()%20%0A" message="" highlight="" provider="manual"/]However, a coroutine can’t start receiving data right away and we’ll get an error when we try to do so. We first need to prime it. This can be done easily by doing:[pastacode lang="python" manual="%20coro.send(None)%20%23%20prints%20out%20Ready%20to%20check%20for%20names.%0A" message="" highlight="" provider="manual"/]Now, we can start sending some data to our coroutine, and this is done by making use of the send method.[pastacode lang="python" manual="coro.send(%22Dennis%22)%20%23%20prints%20out%20Found%0Acoro.send(%22Captain%22)%20%23%20prints%20out%20Not%20found%0A" message="" highlight="" provider="manual"/]An important thing to note is if our generator or coroutine does not have a breakpoint, we can manually stop it by doing:[pastacode lang="python" manual="coro.close()%0A" message="" highlight="" provider="manual"/]That’s it for now, I hope this was helpful in beginning to understand generators and coroutines. You can read more from these resources:

READ: How to build your own version of React from scratch (Part 1)

Related posts

The latest articles from Andela.

Visit our blog

Overcoming the Challenges of Working With a Mobile FinTech API

Andela community member Zzwia Raymond explores why, despite the potential of the MTN Mobile Money platform and its API, there are technical hurdles, from complex documentation to enhancing functionality.

How Andela Transformed Tech Hiring in 10 Years

Celebrating 10 years of transforming tech hiring by unlocking global talent across Africa, Latin America and beyond, Andela has surpassed its original goal by training nearly 110,000 technologists and assembling one of the world's largest remote tech talent marketplaces.

What GPT-4o and Gemini releases mean for AI

The latest generative AI models from OpenAI (GPT-4) and Google (Gemini 1.5 Pro, Veo, etc.) promise improved capabilities, lower costs, and transformative applications across various industries by integrating advanced AI technologies into business operations.

We have a 96%+
talent match success rate.

The Andela Talent Operating Platform provides transparency to talent profiles and assessment before hiring. AI-driven algorithms match the right talent for the job.