Python Coroutine Usage Tutorial – Complete Guide

In this comprehensive guide, we are going to immerse ourselves in the world of Python coroutines. If you are on your coding journey and have decided to learn this powerful programming language, you’ve found a valuable resource. Not only is Python renowned for its simplicity and readability, but its deep and rich standard library also allows for some serious versatility.

Python Coroutines:  A Primer

Python coroutines are a special type of function which retains its state in between executions. Unlike normal functions which always resume execution from the beginning, a coroutine can resume execution after yielding a value, from where it left off.

Coroutines are a game-changer when it comes to programming tasks, such as async I/O operations, that require maintaining state in between executions. Not only does this feature make your code more efficient, but it also speeds up your programs drastically. Learning how to use coroutines can quickly take you from an amateur coder to a professional, skilled one.

The Importance of Coroutines

Python coroutines make asynchronous code resemble synchronous code, making it easier to read and debug. Since Python, the world’s fastest-growing and one of the most popular programming languages, is extensively used in data science, machine learning, and other high-demand sectors, mastery of Python coroutines is a highly sought-after skill in the current job market.

Being familiar with Python coroutines gives you an edge, allowing you to write efficient programs that have improved readability. This tutorial offers you a definitive exploration into the world of Python coroutines, providing you with clear, detailed examples to help your understanding.

Stay with us till the end as we unfold the mysteries behind Python coroutines and unveil how to use them effectively in your own programs.

CTA Small Image
FREE COURSES AT ZENVA
LEARN GAME DEVELOPMENT, PYTHON AND MORE
ACCESS FOR FREE
AVAILABLE FOR A LIMITED TIME ONLY

Basic Usage of Coroutines

Firstly, let us start with a standard coroutine function. It works similarly to a regular function, except that it can pause and resume its execution. We define a coroutine function in Python using the async def syntax.

async def my_first_coroutine():
    print('Hello, from coroutine!')

Your coroutine doesn’t do anything unless it is called and awaited. To do this, you need an event loop, which is a Python construct that schedules and runs coroutines. Python’s asyncio module provides a main event loop that we will use:

import asyncio

async def my_first_coroutine():
    print('Hello, from coroutine!')

# Run the coroutine on an event loop
asyncio.run(my_first_coroutine())

But what if you want your coroutine to give a result back to the caller? That’s where the return statement comes in, just like in a regular Python function:

import asyncio

async def coroutine_with_return_values():
    return 'Hello from returned coroutine!'

# Retrieve the coroutine's return value
result = asyncio.run(coroutine_with_return_values())

print(result)  # Output: Hello from returned coroutine!

Advanced Coroutine Usage

Suppose you have a few coroutines running at the same time. You can pause one coroutine (yield execution) and continue with another. This is where the async/await syntax shines!

import asyncio

async def count_to_ten():
    for i in range(10):
        print(i)
        await asyncio.sleep(1)

async def say_hello():
    while True:
        print('Hello!')
        await asyncio.sleep(1)

# Run both coroutines on an event loop
asyncio.run(asyncio.gather(count_to_ten(), say_hello()))

The above code will print a number and ‘Hello!’ alternately every second, without any delay between them.

Lastly, you can also handle exceptions within coroutines. Coroutine exceptions work exactly the same as regular Python exceptions:

import asyncio

async def failing_coroutine():
    raise Exception('This coroutine failed!')

try:
    asyncio.run(failing_coroutine())
except Exception as e:
    print(f'Caught an exception: {e}')

In the above example, running the failing coroutine will raise an exception, which you can catch and handle as needed.

Coroutine Chaining and Nesting

Just like standard functions, coroutines can also be chained or nested. Let’s explore this in the next examples:

import asyncio

async def takes_a_while():
    print('This will take 5 seconds...')
    await asyncio.sleep(5)

async def starter_coroutine():
    print('Starting coroutines...')
    await takes_a_while()
    print('Coroutine ended!')

# Run the coroutine chain on an event loop
asyncio.run(starter_coroutine())

The starter_coroutine() awaits the other coroutine, causing it to halt execution until the invoked coroutine completes its job.

Concurrency with Asyncio

Asynchronous programming’s main highlight is allowing multiple operations to seemingly happen at once, thus improving performance in programs. We can look at an example where asyncio dramatically improves speed:

import asyncio
import time 

async def count():
    print("One")
    await asyncio.sleep(1)
    print("Two")

async def main():
    await asyncio.gather(count(), count(), count())

s = time.perf_counter()
asyncio.run(main())
elapsed = time.perf_counter() - s
print(f"Executed in {elapsed:0.2f} seconds.")

In the above example, three coroutines of function count() run concurrently, taking only one second to complete rather than three seconds if run sequentially.

Error Handling in Coroutines

When it comes to async code, it’s also important to include exceptions handling just like we do in synchronous code.

import asyncio

async def raises_error():
    raise ValueError('Something went wrong')

async def main():
    try:
        await raises_error()
    except ValueError as e:
        print(f"Catched error: {e}")

asyncio.run(main())

This piece of code demonstrates how exception handling works. When a ValueError is raised in raises_error() function, main() function handles the error gracefully and continues execution.

Cancellation of Coroutines

Python’s asyncio allows you to cancel running coroutines, which can help in situations where you want to terminate a long-running or hanging operation.

import asyncio

async def long_running_task():
    for i in range(5):
        await asyncio.sleep(1)
        print(f'Done task {i}')

async def main():
    task = asyncio.create_task(long_running_task())
    await asyncio.sleep(3)
    print("Cancelling long running task!")
    task.cancel()
    try:
        await task
    except asyncio.CancelledError:
        print("Task was cancelled!")

asyncio.run(main())

In this code snippet, we’re launching a long_running_task() coroutine that takes 5 seconds to complete. However, the coroutine gets cancelled after 3 seconds.

Where to Go Next?

Armed with the knowledge you’ve gained from this tutorial on Python coroutines, you might be wondering, “where do I go next?” Continue your journey of mastering Python with us!

If you’re keen to dive deeper into Python, check out our Python Mini-Degree. This comprehensive collection of courses on Python programming covers basics, algorithms, object-oriented programming, game development, and app development using popular libraries and frameworks like Pygame, Tkinter, and Kivy.

The Python Mini-Degree is designed for learners of all levels, with flexible learning options and project-based assignments. Python’s versatility offers numerous career opportunities in industries such as data science, AI, game development, and more. Our courses are updated regularly to align with industry practices ensuring that you stay ahead in your career.

Or, explore our wide array of Python courses. This broader collection offers you a tailored experience, whether you’re interested in specific Python applications or looking to refresh your basic skills. By investing time in enhancing your Python knowledge with us, you’re setting yourself up for numerous potential career opportunities.

Conclusion

Whether you’re new to Python or a seasoned programmer, gaining a deeper understanding of Python coroutines and mastering the asyncio library is a significant achievement. Python coroutines can help make your code cleaner, easier to read, and most importantly, more efficient, adding a serious boost to your programming skill set.

Never stop learning! Keep going with our Python Mini-Degree to solidify your understanding and broaden your knowledge of Python’s vast ecosystem. We at Zenva are excited to be part of your programming journey, here to help you augment your skills and open new doors of opportunities.

Did you come across any errors in this tutorial? Please let us know by completing this form and we’ll look into it!

FREE COURSES
Python Blog Image

FINAL DAYS: Unlock coding courses in Unity, Godot, Unreal, Python and more.