Search icon CANCEL
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Clean Code in Python

You're reading from   Clean Code in Python Develop maintainable and efficient code

Arrow left icon
Product type Paperback
Published in Jan 2021
Publisher Packt
ISBN-13 9781800560215
Length 422 pages
Edition 2nd Edition
Languages
Arrow right icon
Author (1):
Arrow left icon
Mariano Anaya Mariano Anaya
Author Profile Icon Mariano Anaya
Mariano Anaya
Arrow right icon
View More author details
Toc

Table of Contents (13) Chapters Close

Preface 1. Introduction, Code Formatting, and Tools 2. Pythonic Code FREE CHAPTER 3. General Traits of Good Code 4. The SOLID Principles 5. Using Decorators to Improve Our Code 6. Getting More Out of Our Objects with Descriptors 7. Generators, Iterators, and Asynchronous Programming 8. Unit Testing and Refactoring 9. Common Design Patterns 10. Clean Architecture 11. Other Books You May Enjoy
12. Index

A brief introduction to asynchronous code

Asynchronous programming is not related to clean code. Therefore, the features of Python described in this section won't make the code base easier to maintain. This section introduces the syntax in Python to work with coroutines, because it might be of use for the reader, and examples with coroutines might appear later in the book.

The idea behind asynchronous programming is to have parts in our code that are able to suspend so that other parts of our code can run. Typically, when we are running I/O operations, we would very much like to keep that code running, and use the CPU on something else during that time.

This changes the programming model. Instead of us making calls synchronously, we would write our code in a way that is being called by an event loop, which is in charge of scheduling the coroutines for running all of them in the same process and thread.

The idea is that we create a series of coroutines, and they're added to the event loop. When the event loop starts, it'll pick among the coroutines it has, and schedule them to run. At some point, when one of our coroutines needs to do an I/O operation, we can trigger it and signal the event loop back to take control again, and then schedule another coroutine whilst this operation was kept running. At some point, the event loop will resume our coroutine from the last point it got stopped at, and will continue from there. Keep in mind that the advantage of asynchronous programming is to not block on I/O operations. This means the code can jump to something else while an I/O operation is in place and then come back at it, but it doesn't mean that there are multiple processes running simultaneously. The execution model is still single-threaded.

In order to achieve this in Python, there were (and still are) lots of frameworks available. But in older versions of Python, there wasn't a specific syntax that allowed this, so the way the frameworks worked was a bit complicated, or non-obvious at first glance. Starting with Python 3.5, specific syntax for declaring coroutines was added to the language, and that changed the way we write asynchronous code in Python. Slightly prior to that, a default event loop module, asyncio, was introduced in the standard library. With these two milestones of Python, making asynchronous programming is much better.

While this section uses asyncio as the module for asynchronous processing, this is not the only one. You can write asynchronous code using any library (there are plenty of them available outside the standard library, such as trio (https://github.com/python-trio/trio) and curio (https://github.com/dabeaz/curio) to name just a couple). The syntax that Python provides for writing coroutines can be considered an API. As long as the library you choose complies with that API, you should be able to use it, without having to change how your coroutines were declared.

The syntactic differences compared with asynchronous programming are that coroutines are like functions, but they're defined with async def before their name. When inside a coroutine and we want to call another one (which can be ours, or defined in a third-party library), we would typically use the await keyword before its invocation. When await is called, this signals the event loop to take back control. At this point, the event loop will resume its execution, and the coroutine will be left there waiting for its non-blocking operation to continue, and in the meantime, another part of the code will run (another coroutine will be called by the event loop). At some point, the event loop will call our original coroutine again, and this one will resume from the point where it left off (right after the line with the await statement).

A typical coroutine we might define in our code has the following structure:

async def mycoro(*args, **kwargs):
    # … logic
    await third_party.coroutine(…)
    # … more of our logic

As mentioned before, there's new syntax for defining coroutines. One difference that this syntax introduces is that as opposed to regular functions, when we call this definition, it will not run the code within it. Instead, it will create a coroutine object. This object will be included in the event loop, and at some point, must be awaited (otherwise the code inside the definition will never run):

result = await mycoro(…)   #  doing result = mycoro() would be erroneous

Don't forget to await your coroutines, or their code will never be run. Pay attention to the warnings given by asyncio.

As mentioned, there are several libraries for asynchronous programming in Python, with event loops that can run coroutines like the preceding one defined. In particular, for asyncio, there's a built-in function to run a coroutine until its completion:

import asyncio
asyncio.run(mycoro(…))

The details of how coroutines work in Python are beyond the scope of this book, but this introduction should get the reader more familiar with the syntax. That said, coroutines are technically implemented on top of generators, which we will explore in detail in Chapter 7, Generators, Iterators, and Asynchronous Programming.

You have been reading a chapter from
Clean Code in Python - Second Edition
Published in: Jan 2021
Publisher: Packt
ISBN-13: 9781800560215
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime