await

Updated March 26, 2026 · Keywords
await async asyncio concurrency

Syntax

The await keyword suspends execution of an async function until the awaited awaitable is complete. It may only be used inside a function declared with async def.

await expression
```python

It is a **syntax error** to use `await` outside an `async def` body. The Python parser raises `SyntaxError: 'await' outside async function` before any code runs.

## What `await` Does

When execution reaches `await expression`, three things happen in sequence:

1. **Suspend** — the calling async function pauses at the `await` line. Local variables are preserved on the call stack.
2. **Yield control** — the event loop is free to run other scheduled tasks.
3. **Resume** — when the awaited awaitable finishes, the event loop schedules the caller to continue. The `await` expression returns the awaitable's result, or raises its exception.

This cooperative yielding is the foundation of Python's single-threaded concurrency model. No thread switching occurs — the event loop drives all async tasks on one thread.

```python
import asyncio

async def fetch():
    await asyncio.sleep(1)
    return 42

async def main():
    result = await fetch()
    print(result)

asyncio.run(main())
# output: 42
```python

In this example, `main()` suspends at `await fetch()` and yields to the event loop. When `fetch()` completes after one second, `main()` resumes and receives the value `42`.

## Awaitable Types

The operand of `await` must be an **awaitable**: any object that implements `__await__()`. Python defines three built-in awaitable types:

| Type | Created by | Notes |
|------|-----------|-------|
| Coroutine | Calling an `async def` function | Most common |
| `Task` | `asyncio.create_task()` | Scheduled on the event loop |
| `Future` | `asyncio` internals or `loop.create_future()` | Low-level, result set by callback |

### Coroutine

Every `async def` function returns a coroutine object when called. That object is awaitable:

```python
async def get_data():
    return "data"

coro = get_data()       # coroutine object — not yet running
result = await coro      # executes get_data(), returns "data"
```python

A coroutine does nothing until it is awaited or passed to `asyncio.create_task()`.

### Task

`asyncio.Task` wraps a coroutine and schedules it on the event loop. Tasks are created implicitly by helpers like `asyncio.create_task()` and can be awaited like coroutines:

```python
async def step(n):
    await asyncio.sleep(n * 0.1)
    return n * 10

async def main():
    task = asyncio.create_task(step(2))
    result = await task   # waits for this specific task
    print(result)

asyncio.run(main())
# output: 20
```python

### Future

`asyncio.Future` is a low-level awaitable whose result is set asynchronously, usually by the event loop or an I/O operation. You rarely create Futures directly, but APIs like `asyncio.wait_for()` accept and wrap them:

```python
async def main():
    loop = asyncio.get_running_loop()
    fut = loop.create_future()
    loop.call_soon(lambda: fut.set_result("done"))
    result = await fut
    print(result)

asyncio.run(main())
# output: done
```python

## Common Patterns

### `asyncio.create_task()`

Schedules a coroutine as a concurrent task. The call returns immediately with a `Task`, before the coroutine has run:

```python
import asyncio

async def task_a():
    await asyncio.sleep(1)
    return "A done"

async def task_b():
    await asyncio.sleep(0.5)
    return "B done"

async def main():
    t1 = asyncio.create_task(task_a())
    t2 = asyncio.create_task(task_b())
    r1 = await t1
    r2 = await t2
    print(r1, r2)

asyncio.run(main())
# output: A done B done
```python

Both tasks run concurrently. `task_b()` finishes in 0.5 seconds while `task_a()` sleeps for 1 second, so `B done` prints before `A done`.

### `asyncio.gather()`

Awaits multiple awaitables concurrently and returns results as a list in input order:

```python
import asyncio

async def step(n):
    await asyncio.sleep(n * 0.1)
    return n * 10

async def main():
    results = await asyncio.gather(step(1), step(2), step(3))
    print(results)

asyncio.run(main())
# output: [10, 20, 30]
```python

`step(1)`, `step(2)`, and `step(3)` all run at the same time. After 0.3 seconds (the longest sleep), all three have completed and `gather` returns the ordered list of results.

### `asyncio.wait_for()`

Adds a timeout to any awaitable. Raises `asyncio.TimeoutError` if the deadline passes before completion:

```python
import asyncio

async def slow():
    await asyncio.sleep(5)
    return "finished"

async def main():
    try:
        result = await asyncio.wait_for(slow(), timeout=1.0)
        print(result)
    except asyncio.TimeoutError:
        print("timed out")

asyncio.run(main())
# output: timed out
```python

`slow()` takes 5 seconds, but `wait_for()` cancels it after 1 second and raises `TimeoutError`. This pattern is essential for building responsive async applications.

### `asyncio.shield()`

Prevents a critical awaitable from being cancelled when its caller is cancelled. If the caller times out or is otherwise cancelled, `shield()` keeps the underlying task alive:

```python
import asyncio

async def critical():
    await asyncio.sleep(3)
    return "critical done"

async def main():
    task = asyncio.create_task(critical())
    try:
        result = await asyncio.wait_for(asyncio.shield(task), timeout=1.0)
        print(result)
    except asyncio.TimeoutError:
        print("shielded task still running in background")
        await task  # wait for it to finish properly

asyncio.run(main())
# output: shielded task still running in background
# (after ~3s): task completes
```python

`wait_for()` times out after 1 second, but `asyncio.shield(task)` prevents the cancellation from propagating to `critical()`. The caller reports the timeout while the critical task continues running in the background.

## SyntaxError: `await` Outside `async def`

Using `await` outside an `async def` body is a hard syntax error. The Python parser rejects it at parse time — no execution possible.

```python
# Module level — SyntaxError
await asyncio.sleep(1)
# SyntaxError: 'await' outside async function
```python

```python
# Inside a regular function — SyntaxError
def blocking():
    await asyncio.sleep(1)
    # SyntaxError: 'await' outside async function
```python

```python
# Inside a lambda — SyntaxError
f = lambda: await asyncio.sleep(1)
# SyntaxError: 'await' outside async function
```python

The only valid contexts for `await` are:

- Inside the body of an `async def` function
- Inside a coroutine or async generator body

## See Also

- [`async` keyword](/reference/keywords/async-keyword/) — defines async functions and generators
- [`asyncio` module](/reference/modules/asyncio-module/) — `create_task()`, `gather()`, `wait_for()`, `shield()`