This is a quick post about async with which (spoiler alert) is the async version of context manager. It’s useful for maintaining resources that need awaits or async calls in enter and exit methods.

context manager Link to heading

First, let’s do a small example for context manager.

with open('f.txt', 'w') as f:
    f.write('write this')
class FileManager(object):
    def __init__(self, fname, perm):
        print("__init__")
        self.obj = open(fname, perm)
    def __enter__(self):
        print("__enter__")
        return self.obj
    def __exit__(self, type, value, traceback):
        print("__exit__")
        self.obj.close()
with FileManager('demo.txt', 'w') as opened_file:
    opened_file.write('sup!')

The output would be something like this:

__init__
__enter__
4
__exit__

async with Link to heading

It’s just the async version of context manager with __aenter__ and __aexit__

import asyncio
class AsyncFileManager(object):
    def __init__(self, fname, perm):
        print("__init__")
        self.obj = open(fname, perm)
    async def __aenter__(self):
        print("__aenter__")
        await asyncio.sleep(1)
        return self.obj
    async def __aexit__(self, type, value, traceback):
        print("__aexit__")
        await asyncio.sleep(1)
        self.obj.close()

async def main():
     async with AsyncFileManager("f.txt","w") as resource:
         print(f"Using {resource}")
asyncio.run(main())

The output as expected is

__init__
__aenter__
Using <_io.TextIOWrapper name='f.txt' mode='w' encoding='UTF-8'>
__aexit__