async and await
Threads let the operating system switch between them at any moment. asyncio takes another route: one thread, and tasks that hand over control only at the points you mark with await.
import asyncio
async def size_of(name):
await asyncio.sleep(0.01) # pretend I/O
return len(name)
async def main():
a = await size_of("notes.txt")
b = await size_of("todo.md")
return a + b
print(asyncio.run(main())) # 16async defdefines a coroutine function. Calling it runs nothing: it returns a coroutine object.awaitruns a coroutine to its result. While it waits, the event loop can run other work.asyncio.run(main())starts an event loop, runsmainto the end and closes the loop. Call it once, from ordinary code.
await only works inside async def. Forgetting it is the classic mistake: you get a coroutine object instead of a value, and Python warns that the coroutine was never awaited.
Your task
Write async def total_size(names, size_of) that awaits size_of(name) for each name, in order, and returns the sum. Then write an ordinary function report(names, size_of) that runs it with asyncio.run and returns a string such as "16 bytes".
The explanation opens here once every check passes.