My App
Phase 8 — async / await

def, async def & await

Same idea as JS async/await — almost the same keywords too

def vs. async def

A normal function runs synchronously, start to finish, exactly like a normal JS function:

def get_user():
    ...

Adding async before def makes it an asynchronous function — one that can pause and resume, without blocking the rest of the program while it waits:

async def get_user():
    ...
async function getUser() {
  // ...
}

Same keyword, same idea, just placed before def instead of before function.

await

Inside an async def function, await pauses at that line until whatever you're awaiting finishes — then resumes with its result. This is the exact same mental model as JS:

async def get_user():
    data = await fetch_data()
    return data
async function getUser() {
  const data = await fetchData();
  return data;
}

Just like JS, await can only be used inside an async def function — not in a regular one.

A real difference from JS: calling an async function

In JS, calling an async function starts running it immediately, whether or not you await the result. In Python, calling an async def function does not run it at all — it just creates a "coroutine" object that sits there, inert, until something actually awaits or schedules it:

get_user()   # does nothing yet! just creates a coroutine object

To actually run one at the top level of a plain script, Python needs an event loop:

import asyncio

result = asyncio.run(get_user())

You won't usually write asyncio.run() yourself once you're inside a framework — in FastAPI, you just write your route handlers as async def, and FastAPI's own event loop runs them for you. This "nothing happens until awaited" behavior is the one habit worth internalizing now, since it's the most common source of confusion moving from JS to Python.

On this page