Что такое контекстные переменные (contextvars)?python-40

Контекстные переменные — это механизм для хранения и передачи данных в рамках определенного контекста выполнения, особенно полезный в асинхронном коде. Они были введены в Python 3.7 как часть модуля contextvars.

Основные понятия

  1. Контекст (Context) — изолированное пространство для хранения переменных
  2. Контекстная переменная (ContextVar) — переменная, значение которой зависит от контекста выполнения
  3. Токен (Token) — объект для восстановления предыдущего значения переменной

Создание и использование

import contextvars

# Создаем контекстную переменную
user_id = contextvars.ContextVar('user_id', default=None)

# Устанавливаем значение в текущем контексте
token = user_id.set(123)

# Получаем значение
print(user_id.get())  # Выведет: 123

# Восстанавливаем предыдущее значение
user_id.reset(token)

Особенности работы

  1. Потокобезопасность (Thread Safety):

    • Каждый поток имеет свой контекст
    • Значения не "протекают" между потоками
  2. Асинхронная поддержка (Async Support):

    • Корректно работают в цепочках async/await
    • Сохраняются при переключении между задачами
import asyncio
import contextvars

request_id = contextvars.ContextVar('request_id')

async def process_request():
    # У каждого вызова будет свое значение
    request_id.set(id(request))
    await some_async_operation()
    print(f"Processing request {request_id.get()}")

async def some_async_operation():
    # Все еще имеет доступ к правильному request_id
    print(f"Operation for {request_id.get()}")

Практические примеры

  1. Трассировка запросов (Request Tracing):
from fastapi import Request
import contextvars

current_request = contextvars.ContextVar('current_request')

async def middleware(request: Request):
    token = current_request.set(request)
    try:
        return await call_next(request)
    finally:
        current_request.reset(token)
  1. Хранение пользовательских данных (User Context):
user_context = contextvars.ContextVar('user_context')

def auth_middleware(request):
    user_data = authenticate(request)
    token = user_context.set(user_data)
    request.state.cleanup = lambda: user_context.reset(token)

Ограничения

  1. Не заменяют собой thread-local переменные для синхронного кода
  2. Некоторый оверхед по производительности
  3. Требуют явного управления жизненным циклом (set/reset)

Сравнение с альтернативами

Метод Потоки Async Изоляция контекста
Global variables
Thread-local
contextvars

Резюмируем

contextvars — мощный инструмент для управления состоянием в асинхронных приложениях и микросервисных архитектурах, обеспечивающий изолированный контекст выполнения для каждого запроса или цепочки вызовов. Они особенно полезны в веб-фреймворках и распределенных системах для передачи метаданных между компонентами.