9.1 Context Managers
Remember how we used the with
statement to control access to resources? It let us track exactly when a resource started being used and when it stopped. The same goes for "async resources."
Async context managers (AsyncContextManager)
are used for managing resources in asynchronous programming, ensuring proper opening and closing of resources within async functions. They work similarly to regular context managers but are designed for async functions with the async with
keywords.
I'm not gonna dive too deep here, since you probably won't be creating your own async context managers anytime soon, and by the time you're ready to do that, you'll likely forget all this. But I do want you to get the idea.
Creating an Async Context Manager
Async context managers are defined using the methods __aenter__
and __aexit__
. These methods are similar to the __enter__
and __exit__
methods in regular context managers but are asynchronous.
-
__aenter__()
: An async method that gets called when entering the context. -
__aexit__(exc_type, exc, tb)
: An async method that gets called when exiting the context. It takes three arguments: the exception type, the exception itself, and thetraceback
.
Example of Creating an Async Context Manager
import asyncio
class AsyncContextManager:
async def __aenter__(self):
print("Enter context")
return self
async def __aexit__(self, exc_type, exc, tb):
print("Exit context")
async def main():
async with AsyncContextManager():
print("Inside context")
asyncio.run(main())
Here's how this code runs:
- The
main()
function starts asynchronously - The
main()
function begins executing - An
AsyncContextManager
object is created - The
AsyncContextManager
's__aenter__()
method is called print("Enter context")
is executed- The
print("Inside context")
code runs - The
AsyncContextManager
's__aexit__()
method is called - The
main()
function finishes execution
9.2 Usage Examples
In the example above, you don't necessarily need to use the async version of the context manager — the code would work even if it were synchronous.
But an async manager is necessary if inside the with
block you call an async function or use the await
keyword.
Async Context Manager for File Operations
This example uses the aiofiles
library for asynchronous file reading and writing. The async context manager aiofiles.open
allows files to be safely opened and closed in an async context.
import aiofiles
import asyncio
async def main():
async with aiofiles.open('example.txt', mode='w') as file:
await file.write('Hello, world!')
asyncio.run(main())
Async Context Manager for Network Operations
This example uses the aiohttp
library for making asynchronous HTTP requests. Async context managers ClientSession
and session.get
ensure proper management of connections.
import aiohttp
import asyncio
async def fetch(url):
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
return await response.text()
async def main():
html = await fetch('https://example.com')
print(html)
asyncio.run(main())
Async context managers automatically manage resources like files, network connections, and other resources that need to be opened and closed.
The __aenter__
and __aexit__
methods allow you to perform async operations upon entering and exiting the context, allowing for parallel task execution. Using async context managers helps prevent resource leaks and ensures all resources are properly released.
GO TO FULL VERSION