liveBook · Manning

Context variable

As explained in Python Concurrency with asyncio

A context variable is state whose value is local to an asynchronous execution context and can be accessed without passing it explicitly through function arguments.

A context variable stores state local to an asynchronous task. Inner coroutines and tasks inherit access to it, while unrelated tasks cannot see or modify it. Unlike thread-local state, it works within asyncio’s single-threaded concurrency model, letting APIs share task-specific state without adding explicit parameters. section 14.2

Tracking a connected client

A server defines ContextVar('user_address'), sets it when a client connects, and lets the message-listening task print the client address alongside each message. section 14.2

Listing 14.2 A server with a context variables
import asyncio
from asyncio import StreamReader, StreamWriter
from contextvars import ContextVar
 
 
class Server:
    user_address = ContextVar('user_address')                             #1
 
    def __init__(self, host: str, port: int):
        self.host = host
        self.port = port
 
    async def start_server(self):
        server = await asyncio.start_server(self._client_connected,
                                            self.host, self.port)
        await server.serve_forever()
 
    def _client_connected(self, reader: StreamReader, writer: StreamWriter):
        self.user_address.set(writer.get_extra_info('peername'))          #2
        asyncio.create_task(self.listen_for_messages(reader))
 
    async def listen_for_messages(self, reader: StreamReader):
        while data := await reader.readline():
            print(f'Got message {data} from {self.user_address.get()}')   #3
 
 
async def main():
    server = Server('127.0.0.1', 9000)
    await server.start_server()
 
 
asyncio.run(main())

Runnable server listing showing ContextVar creation, connection-time assignment, task creation, and per-client message output. section 14.2

How Python Concurrency with asyncio covers it

How deep it goes
Defines task-local inheritance, demonstrates ContextVar in a server, and stops short of deeper implementation details.
Examples
Uses a client server that records each connected user’s address and prints it with incoming messages.
What it assumes
Assumes asyncio tasks and coroutines, while contrasting their state model with thread locals.
What you can do after
Apply it via ContextVar to propagate per-task state through spawned coroutines without explicit argument passing.
How it connects
Connects context variables to thread locals, asyncio tasks, coroutines, and single-threaded concurrency.

Also explained in

Compare how 2 books explain context variable →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Python Concurrency with asyncio. The section links point to the parts of the book it draws on.