contextvars — Контекстные переменные
Этот модуль предоставляет API для управления состоянием, локальным для контекста, его хранения и доступа к нему. Класс ContextVar используется для объявления и работы с контекстными переменными. Функция copy_context() и класс Context предназначены для управления текущим контекстом в асинхронных платформах.
Менеджерам контекста, содержащим состояние, следует использовать контекстные переменные вместо threading.local(), чтобы при использовании в конкурентном коде их состояние неожиданно не попадало в другой код.
Дополнительные сведения см. также в PEP 567.
Добавлено в версии 3.7.
Контекстные переменные
-
class contextvars.ContextVar(name[, *, default]) -
Этот класс используется для объявления новой контекстной переменной, например:
var: ContextVar[int] = ContextVar('var', default=42)Обязательный параметр name используется для интроспекции и отладки.
Необязательный именованный параметр default возвращается методом
ContextVar.get(), если в текущем контексте для переменной не найдено значение.Важно: контекстные переменные следует создавать на верхнем уровне модуля, а не внутри замыканий. Объекты
Contextсодержат сильные ссылки на контекстные переменные, что мешает их корректному удалению сборщиком мусора.-
name -
Имя переменной. Это свойство доступно только для чтения.
Добавлено в версии 3.7.1.
-
get([default]) -
Возвращает значение контекстной переменной для текущего контекста.
Если в текущем контексте для переменной нет значения, метод:
- возвращает значение аргумента default метода, если он указан; или
- возвращает значение по умолчанию для контекстной переменной, если оно было задано при её создании; или
- вызывает исключение
LookupError.
-
set(value) -
Устанавливает новое значение контекстной переменной в текущем контексте.
Обязательный аргумент value — новое значение контекстной переменной.
Возвращает объект
Token, который можно использовать для восстановления прежнего значения переменной с помощью методаContextVar.reset().
-
reset(token) -
Сбрасывает контекстную переменную к значению, которое она имела до вызова метода
ContextVar.set(), создавшего token.Например:
var = ContextVar('var') token = var.set('new value') # code that uses 'var'; var.get() returns 'new value'. var.reset(token) # After the reset call the var has no value again, so # var.get() would raise a LookupError.
-
-
class contextvars.Token -
Объекты Token возвращаются методом
ContextVar.set(). Их можно передать методуContextVar.reset(), чтобы восстановить значение переменной, которое было до соответствующего вызова set.-
var -
Свойство доступно только для чтения. Ссылается на объект
ContextVar, создавший токен.
-
old_value -
Свойство доступно только для чтения. Содержит значение переменной до вызова метода
ContextVar.set(), создавшего токен. Если до вызова переменной не было присвоено значение, свойство ссылается наToken.MISSING.
-
MISSING -
Объект-маркер, используемый свойством
Token.old_value.
-
Ручное управление контекстом
-
contextvars.copy_context() -
Возвращает копию текущего объекта
Context.Следующий фрагмент получает копию текущего контекста и выводит все переменные, установленные в нём, вместе с их значениями:
ctx: Context = copy_context() print(list(ctx.items()))
Функция имеет сложность O(1), то есть работает одинаково быстро как для контекстов с небольшим числом контекстных переменных, так и для контекстов с большим их числом.
-
class contextvars.Context -
Отображение
ContextVarsна их значения.Конструктор
Context()создаёт пустой контекст без значений. Чтобы получить копию текущего контекста, используйте функциюcopy_context().У каждого потока есть отдельный объект
Contextверхнего уровня. Это означает, что объектContextVarведёт себя аналогичноthreading.local(), когда значения присваиваются в разных потоках.Context реализует интерфейс
collections.abc.Mapping.-
run(callable, *args, **kwargs) -
Выполняет код
callable(*args, **kwargs)в объекте контекста, для которого вызван метод run. Возвращает результат выполнения или передаёт возникшее исключение.Все изменения контекстных переменных, внесённые объектом callable, будут сохранены в объекте контекста:
var = ContextVar('var') var.set('spam') def main(): # 'var' was set to 'spam' before # calling 'copy_context()' and 'ctx.run(main)', so: # var.get() == ctx[var] == 'spam' var.set('ham') # Now, after setting 'var' to 'ham': # var.get() == ctx[var] == 'ham' ctx = copy_context() # Any changes that the 'main' function makes to 'var' # will be contained in 'ctx'. ctx.run(main) # The 'main()' function was run in the 'ctx' context, # so changes to 'var' are contained in it: # ctx[var] == 'ham' # However, outside of 'ctx', 'var' is still set to 'spam': # var.get() == 'spam'Метод вызывает исключение
RuntimeError, если он вызван для одного и того же объекта контекста из нескольких потоков ОС или рекурсивно.
-
copy() -
Возвращает поверхностную копию объекта контекста.
- var in context
-
Возвращает
True, если для var в context задано значение; в противном случае возвращаетFalse.
- context[var]
-
Возвращает значение переменной
ContextVarvar. Если переменная не задана в объекте контекста, вызывается исключениеKeyError.
-
get(var[, default]) -
Возвращает значение для var, если оно задано в объекте контекста. В противном случае возвращает default. Если default не указан, возвращает
None.
- iter(context)
-
Возвращает итератор по переменным, хранящимся в объекте контекста.
- len(proxy)
-
Возвращает количество переменных, заданных в объекте контекста.
-
keys() -
Возвращает список всех переменных в объекте контекста.
-
values() -
Возвращает список значений всех переменных в объекте контекста.
-
items() -
Возвращает список 2-элементных кортежей со всеми переменными и их значениями в объекте контекста.
-
Поддержка asyncio
Контекстные переменные изначально поддерживаются в asyncio и готовы к использованию без дополнительной настройки. Например, вот простой эхо-сервер, который использует контекстную переменную, чтобы адрес удалённого клиента был доступен в задаче, обрабатывающей запросы этого клиента:
import asyncio
import contextvars
client_addr_var = contextvars.ContextVar('client_addr')
def render_goodbye():
# The address of the currently handled client can be accessed
# without passing it explicitly to this function.
client_addr = client_addr_var.get()
return f'Good bye, client @ {client_addr}\r\n'.encode()
async def handle_request(reader, writer):
addr = writer.transport.get_extra_info('socket').getpeername()
client_addr_var.set(addr)
# In any code that we call is now possible to get
# client's address by calling 'client_addr_var.get()'.
while True:
line = await reader.readline()
print(line)
if not line.strip():
break
writer.write(b'HTTP/1.1 200 OK\r\n') # status line
writer.write(b'\r\n') # headers
writer.write(render_goodbye()) # body
writer.close()
async def main():
srv = await asyncio.start_server(
handle_request, '127.0.0.1', 8081)
async with srv:
await srv.serve_forever()
asyncio.run(main())
# To test it you can use telnet or curl:
# telnet 127.0.0.1 8081
# curl 127.0.0.1:8081
© 2001–2024 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.12/library/contextvars.html