We're sorry but this app doesn't work properly without JavaScript enabled. Please enable it to continue.

This lesson's interactive features are locked, please to keep using them

Coroutines and Context Managers

The asyncio library gives us the tools to run many tasks concurrently using coroutines. We can define functions with async def, which marks the function as a coroutine – a special kind of function that can be paused and resumed later. Inside these functions, you can use the await keyword to pause execution until another coroutine has finished. This makes it possible to run multiple operations at the same time without blocking the entire program.

In upcoming assignments, I'll be referencing the with and async with keywords. These are just syntactic sugar for using "context managers". Context manager are just classes that define __enter__ and __exit__ (or for async: __aenter__ and __aexit__.) These methods are used to set things up and clean them up automatically – often when dealing with resources like files, network connections, or locks.

A classic example is working with files. When you open a file, it's important to close it after you're done. Context managers make this easy by handling that cleanup for you:

# without "with"
file = open("my_file.txt", "w")
file.write("Boots was here!")
file.close()

# using "with"
with open("my_file.txt", "w") as file:
    file.write("Boots was here!")

When the with block exits, Python automatically calls file.close() behind the scenes, even if an error occurs while working with the file. The async with version works the same way for asynchronous resources.