contextvars
— Variáveis de contexto¶
Este módulo fornece APIs para gerenciar, armazenar e acessar o estado local do contexto. A classe ContextVar
é usada para declarar e trabalhar com Variáveis de Contexto. A função copy_context()
e a classe Context
devem ser usadas para gerenciar o contexto atual em frameworks assíncronos.
Os gerenciadores de contexto que possuem estado devem usar Variáveis de Contexto ao invés de threading.local()
para evitar que seu estado vaze para outro código inesperadamente, quando usado em código concorrente.
Veja também a PEP 567 para detalhes adicionais.
Novo na versão 3.7.
Variáveis de contexto¶
-
class
contextvars.
ContextVar
(name[, *, default])¶ Esta classe é usada para declarar uma nova variável de contexto, como, por exemplo:
var: ContextVar[int] = ContextVar('var', default=42)
O parâmetro obrigatório name é usado para fins de introspecção e depuração.
O parâmetro somente-nomeado opcional default é retornado por
ContextVar.get()
quando nenhum valor para a variável é encontrado no contexto atual.Importante: Variáveis de Contexto devem ser criadas no nível do módulo superior e nunca em fechamentos. Os objetos
Context
contêm referências fortes a variáveis de contexto que evitam que as variáveis de contexto sejam coletadas como lixo corretamente.-
name
¶ O nome da variável. Esta é uma propriedade somente leitura.
Novo na versão 3.7.1.
-
get
([default])¶ Retorna um valor para a variável de contexto para o contexto atual.
Se não houver valor para a variável no contexto atual, o método vai:
retornar o valor do argumento default do método, se fornecido; ou
retornar o valor padrão para a variável de contexto, se ela foi criada com uma; ou
levantar uma
LookupError
.
-
set
(value)¶ Chame para definir um novo valor para a variável de contexto no contexto atual.
O argumento value obrigatório é o novo valor para a variável de contexto.
Retorna um objeto
Token
que pode ser usado para restaurar a variável ao seu valor anterior através do métodoContextVar.reset()
.
-
reset
(token)¶ Redefine a variável de contexto para o valor que tinha antes de :meth: ContextVar.set. que criou o token, ser usado.
Por exemplo:
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
¶ Objetos token são retornados pelo método
ContextVar.set()
. Eles podem ser passados para o métodoContextVar.reset()
para reverter o valor da variável para o que era antes do set correspondente.-
Token.
var
¶ Uma propriedade somente leitura. Aponta para o objeto
ContextVar
que criou o token.
-
Token.
old_value
¶ Uma propriedade somente leitura. Defina com o valor que a variável tinha antes da chamada do método
ContextVar.set()
que criou o token. Ele aponta paraToken.MISSING
é a variável não foi definida antes da chamada.
-
Token.
MISSING
¶ Um objeto marcador usado por
Token.old_value
.
-
Gerenciamento de Contexto Manual¶
-
contextvars.
copy_context
()¶ Retorna uma cópia do objeto
Context
atual.O trecho a seguir obtém uma cópia do contexto atual e imprime todas as variáveis e seus valores que são definidos nele:
ctx: Context = copy_context() print(list(ctx.items()))
A função tem uma complexidade O(1), ou seja, funciona igualmente rápido para contextos com algumas variáveis de contexto e para contextos que têm muitas delas.
-
class
contextvars.
Context
¶ Um mapeamento de
ContextVars
para seus valores.Context()
cria um contexto vazio sem valores nele. Para obter uma cópia do contexto atual, use a funçãocopy_context()
.Context implementa a interface
collections.abc.Mapping
.-
run
(callable, *args, **kwargs)¶ Executa o código
callable(*args, **kwargs)
no objeto contexto em que o método run é chamado. Retorna o resultado da execução ou propaga uma exceção, se ocorrer.Quaisquer mudanças em quaisquer variáveis de contexto que callable faça estarão contidas no objeto de contexto:
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'
O método levanta uma
RuntimeError
quando chamado no mesmo objeto de contexto de mais de uma thread do sistema operacional, ou quando chamado recursivamente.
-
copy
()¶ Retorna uma cópia rasa do objeto contexto.
-
var in context
Retorna
True
se context tem uma variável para var definida; do contrário, retornaFalse
.
-
context[var]
Retorna o valor da variável
ContextVar
var. Se a variável não for definida no objeto contexto, umaKeyError
é levantada.
-
get
(var[, default])¶ Retorna o valor para var se var tiver o valor no objeto contexto. Caso contrário, retorna default. Se default não for fornecido, retorna
None
.
-
iter(context)
Retorna um iterador sobre as variáveis armazenadas no objeto contexto.
-
len(proxy)
Retorna o número das variáveis definidas no objeto contexto.
-
keys
()¶ Retorna uma lista de todas as variáveis no objeto contexto.
-
values
()¶ Retorna uma lista dos valores de todas as variáveis no objeto contexto.
-
items
()¶ Retorna uma lista de tuplas de 2 elementos contendo todas as variáveis e seus valores no objeto contexto.
-
Suporte a asyncio¶
Variáveis de contexto encontram suporte nativo em asyncio
e estão prontas para serem usadas sem qualquer configuração extra. Por exemplo, aqui está um servidor simples de eco, que usa uma variável de contexto para disponibilizar o endereço de um cliente remoto na Task que lida com esse cliente:
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}\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(line)
writer.write(render_goodbye())
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:
# telnet 127.0.0.1 8081