Документация Python неофициальный перевод

contextvars.md

233 строк · 13.4 КБ · обычная страница · сырой текст · скачать

1> **Источник:** https://python-all.ru/3.8/library/contextvars.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# [`contextvars`](https://python-all.ru/3.8/library/contextvars.html#module-contextvars) – Контекстные переменные89---1011Этот модуль предоставляет API для управления, хранения и доступа к контекстно-локальному состоянию. Класс [`ContextVar`](https://python-all.ru/3.8/library/contextvars.html#contextvars.ContextVar) используется для объявления и работы с *контекстными переменными*. Функция [`copy_context()`](https://python-all.ru/3.8/library/contextvars.html#contextvars.copy_context) и класс [`Context`](https://python-all.ru/3.8/library/contextvars.html#contextvars.Context) должны использоваться для управления текущим контекстом в асинхронных фреймворках.1213Менеджеры контекста, имеющие состояние, должны использовать контекстные переменные вместо [`threading.local()`](https://python-all.ru/3.8/library/threading.html#threading.local), чтобы предотвратить непреднамеренную утечку своего состояния в другой код при использовании в конкурентном коде.1415См. также [**PEP 567**](https://python-all.ru/3.8/library/contextvars.html) для получения дополнительных сведений.1617Добавлено в версии 3.7.1819## Контекстные переменные2021#### `class contextvars.ContextVar(name[, *, default])`2223Этот класс используется для объявления новой контекстной переменной, например:2425```python26var: ContextVar[int] = ContextVar('var', default=42)27```2829Обязательный параметр *name* используется для целей интроспекции и отладки.3031Необязательный параметр *default*, передаваемый только по ключу, возвращается [`ContextVar.get()`](https://python-all.ru/3.8/library/contextvars.html#contextvars.ContextVar.get), если в текущем контексте не найдено значение для переменной.3233**Важно:** Контекстные переменные должны создаваться на верхнем уровне модуля, а не в замыканиях. Объекты [`Context`](https://python-all.ru/3.8/library/contextvars.html#contextvars.Context) содержат сильные ссылки на контекстные переменные, что препятствует их корректной сборке мусора.3435#### `name`3637Имя переменной. Это свойство только для чтения.3839Новое в версии 3.7.1.4041#### `get([default])`4243Возвращает значение для контекстной переменной в текущем контексте.4445Если в текущем контексте нет значения для переменной, метод:4647- возвращает значение аргумента *default* метода, если он был передан; или48- возвращает значение по умолчанию для контекстной переменной, если она была создана с ним; или49- возбуждает [`LookupError`](https://python-all.ru/3.8/library/exceptions.html#LookupError).5051#### `set(value)`5253Вызов для установки нового значения контекстной переменной в текущем контексте.5455Обязательный аргумент *value* – это новое значение для контекстной переменной.5657Возвращает объект [`Token`](https://python-all.ru/3.8/library/contextvars.html#contextvars.Token), который можно использовать для восстановления предыдущего значения переменной с помощью метода [`ContextVar.reset()`](https://python-all.ru/3.8/library/contextvars.html#contextvars.ContextVar.reset).5859#### `reset(token)`6061Сбрасывает контекстную переменную до значения, которое она имела до вызова [`ContextVar.set()`](https://python-all.ru/3.8/library/contextvars.html#contextvars.ContextVar.set), создавшего *токен*.6263Например:6465```python66var = ContextVar('var')6768token = var.set('new value')69# код, который использует 'var'; var.get() возвращает 'new value'.70var.reset(token)7172# После вызова reset переменная снова не имеет значения, поэтому73# var.get() вызовет исключение LookupError.74```7576#### `class contextvars.Token`7778Объекты *Token* возвращаются методом [`ContextVar.set()`](https://python-all.ru/3.8/library/contextvars.html#contextvars.ContextVar.set). Их можно передать методу [`ContextVar.reset()`](https://python-all.ru/3.8/library/contextvars.html#contextvars.ContextVar.reset), чтобы вернуть значение переменной к тому, которое было до соответствующего *set*.7980#### `var`8182Свойство только для чтения. Указывает на объект [`ContextVar`](https://python-all.ru/3.8/library/contextvars.html#contextvars.ContextVar), который создал токен.8384#### `old_value`8586Свойство только для чтения. Устанавливается в значение, которое переменная имела до вызова метода [`ContextVar.set()`](https://python-all.ru/3.8/library/contextvars.html#contextvars.ContextVar.set), создавшего токен. Оно указывает на [`Token.MISSING`](https://python-all.ru/3.8/library/contextvars.html#contextvars.Token.MISSING), если переменная не была установлена до вызова.8788#### `MISSING`8990Объект-маркер, используемый [`Token.old_value`](https://python-all.ru/3.8/library/contextvars.html#contextvars.Token.old_value).9192## Ручное управление контекстом9394#### `contextvars.copy_context()`9596Возвращает копию текущего объекта [`Context`](https://python-all.ru/3.8/library/contextvars.html#contextvars.Context).9798Следующий фрагмент получает копию текущего контекста и выводит все переменные и их значения, установленные в нём:99100```python101ctx: Context = copy_context()102print(list(ctx.items()))103```104105Функция имеет сложность O(1), то есть работает одинаково быстро как для контекстов с несколькими контекстными переменными, так и для контекстов, содержащих много переменных.106107#### `class contextvars.Context`108109Отображение [`ContextVars`](https://python-all.ru/3.8/library/contextvars.html#contextvars.ContextVar) на их значения.110111`Context()` создаёт пустой контекст без значений. Чтобы получить копию текущего контекста, используйте функцию [`copy_context()`](https://python-all.ru/3.8/library/contextvars.html#contextvars.copy_context).112113Контекст реализует интерфейс [`collections.abc.Mapping`](https://python-all.ru/3.8/library/collections.abc.html#collections.abc.Mapping).114115#### `run(callable, *args, **kwargs)`116117Выполняет код `callable(*args, **kwargs)` в контекстном объекте, для которого вызван метод *run*. Возвращает результат выполнения или распространяет исключение, если оно произошло.118119Любые изменения контекстных переменных, которые делает *callable*, будут содержаться в контекстном объекте:120121```python122var = ContextVar('var')123var.set('spam')124125def main():126    # 'var' было установлено в 'spam' до127    # вызова 'copy_context()' и 'ctx.run(main)', поэтому:128    # var.get() == ctx[var] == 'spam'129130    var.set('ham')131132    # Теперь, после установки 'var' в 'ham':133    # var.get() == ctx[var] == 'ham'134135ctx = copy_context()136137# Любые изменения, которые функция 'main' вносит в 'var'138# будут содержаться в 'ctx'.139ctx.run(main)140141# Функция 'main()' была запущена в контексте 'ctx',142# поэтому изменения 'var' содержатся в нём:143# ctx[var] == 'ham'144145# Однако вне 'ctx' переменная 'var' по-прежнему равна 'spam':146# var.get() == 'spam'147```148149Метод вызывает исключение [`RuntimeError`](https://python-all.ru/3.8/library/exceptions.html#RuntimeError) при вызове для одного и того же контекстного объекта из нескольких потоков ОС или при рекурсивном вызове.150151#### `copy()`152153Возвращает поверхностную копию объекта контекста.154155#### `var in context`156157Возвращает `True`, если в *контексте* установлено значение для *var*; в противном случае возвращает `False`.158159#### `context[var]`160161Возвращает значение переменной *var* [`ContextVar`](https://python-all.ru/3.8/library/contextvars.html#contextvars.ContextVar). Если переменная не установлена в объекте контекста, возбуждается [`KeyError`](https://python-all.ru/3.8/library/exceptions.html#KeyError).162163#### `get(var[, default])`164165Возвращает значение *var*, если *var* имеет значение в объекте контекста. В противном случае возвращает *default*. Если *default* не указан, возвращает `None`.166167#### `iter(context)`168169Возвращает итератор по переменным, хранящимся в объекте контекста.170171#### `len(proxy)`172173Возвращает количество переменных, установленных в объекте контекста.174175#### `keys()`176177Возвращает список всех переменных в объекте контекста.178179#### `values()`180181Возвращает список всех значений переменных в объекте контекста.182183#### `items()`184185Возвращает список кортежей из двух элементов, содержащих все переменные и их значения в объекте контекста.186187## Поддержка asyncio188189Контекстные переменные нативно поддерживаются в [`asyncio`](https://python-all.ru/3.8/library/asyncio.html#module-asyncio) и готовы к использованию без дополнительной настройки. Например, вот простой эхо-сервер, который использует контекстную переменную, чтобы сделать адрес удаленного клиента доступным в задаче, обрабатывающей этого клиента:190191```python192import asyncio193import contextvars194195client_addr_var = contextvars.ContextVar('client_addr')196197def render_goodbye():198    # Адрес текущего обрабатываемого клиента можно получить199    # не передавая его явно в эту функцию.200201    client_addr = client_addr_var.get()202    return f'Good bye, client @ {client_addr}\n'.encode()203204async def handle_request(reader, writer):205    addr = writer.transport.get_extra_info('socket').getpeername()206    client_addr_var.set(addr)207208    # В любом вызываемом нами коде теперь можно получить209    # адрес клиента, вызвав 'client_addr_var.get()'.210211    while True:212        line = await reader.readline()213        print(line)214        if not line.strip():215            break216        writer.write(line)217218    writer.write(render_goodbye())219    writer.close()220221async def main():222    srv = await asyncio.start_server(223        handle_request, '127.0.0.1', 8081)224225    async with srv:226        await srv.serve_forever()227228asyncio.run(main())229230# Для тестирования можно использовать telnet:231#     telnet 127.0.0.1 8081232```233