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
AsyncContextManagerobject 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