
Passo 1 de 8
Delimitar a fronteira de entrada
Posicione uma função validadora entre o JSON externo e o restante do programa, impedindo que um valor dinâmico se espalhe como Any.
Trilha de aprendizado · Nível 12 · Tutorial 11
Construir uma fronteira de entrada que receba dados externos sem garantias, valide sua estrutura e suas regras e entregue valores com um contrato estático confiável.
Delimitar a fronteira de entrada
Posicione uma função validadora entre o JSON externo e o restante do programa, impedindo que um valor dinâmico se espalhe como Any. 2 min
Reconhecer o que não valida os dados
Diferencie afirmações estáticas de verificações reais feitas em tempo de execução. 3 min
Validar a estrutura antes de acessar os campos
Rejeite uma raiz incompatível e chaves obrigatórias ausentes antes de extrair valores ainda não validados. 3 min
Estreitar os tipos de cada campo
Use verificações progressivas para transformar valores locais anotados como object em valores seguros para uso tipado. 4 min
Validar regras que os tipos não expressam
Aplique regras do domínio depois do estreitamento de tipos: normalize o nome, aceite quantidades não negativas e mantenha explícita a política para etiquetas. 3 min
Construir o resultado tipado
Integre todas as verificações em uma função que separa a entrada externa de um Produto construído com valores validados. 3 min
Combinar mypy com testes de rejeição
Use análise estática e testes de execução como evidências complementares para uma fronteira que transforma dados externos em Produto. 4 min
Aplicar e revisar a fronteira completa
Aplique a validação de um Produto, verifique-a localmente e consolide as garantias obtidas na fronteira de entrada. 4 min

Passo 1 de 8
Posicione uma função validadora entre o JSON externo e o restante do programa, impedindo que um valor dinâmico se espalhe como Any.
Texto JSON pode ser desserializado com sucesso e ainda assim ter uma forma incompatível com o programa. Por isso, trate o resultado da desserialização como uma entrada sem garantias.
No caso condutor, o código consumidor precisa receber um Produto com três campos obrigatórios:
nome: strquantidade: intetiquetas: list[str]A função validadora será a fronteira: ela recebe o dado externo, verifica-o nas próximas etapas e só então devolve um Produto — ou sinaliza uma falha.
O valor externo não deve seguir diretamente para o código que depende do contrato.

A validação separa o mundo externo, sem contrato confiável, do código que consome um Produto.
json.loads é dinâmico: seu resultado pode ser qualquer valor JSON. Em vez de deixar esse Any alcançar o restante do programa, atribua-o a uma variável anotada como object e receba object na fronteira.
Isso não verifica nada em tempo de execução. A anotação apenas limita, para o mypy, as operações que você pode fazer antes de justificar o tipo do valor.
Este é apenas o contrato inicial. As verificações que permitem retornar o valor serão construídas nos próximos passos.
import json
from typing import TypedDict
class Produto(TypedDict):
nome: str
quantidade: int
etiquetas: list[str]
def validar_produto(dados: object) -> Produto:
"""Retorna Produto após validar os dados; falha se a entrada for inválida."""
raise NotImplementedError
texto_json = '{"nome": "Cabo USB", "quantidade": 3, "etiquetas": ["eletrônicos"]}'
dado_externo: object = json.loads(texto_json)
produto = validar_produto(dado_externo)
print(produto["nome"])Coloque as etapas na ordem em que devem ocorrer para impedir que dados externos sejam usados como se já fossem um Produto.

Passo 2 de 8
Diferencie afirmações estáticas de verificações reais feitas em tempo de execução.
cast(Produto, valor) diz ao verificador estático: “trate valor como um Produto”. Ele não examina o valor em tempo de execução, não converte seus campos e não cria uma cópia.
Por isso, um cast pode silenciar um diagnóstico do mypy, mas não torna dados externos confiáveis.
Compare uma afirmação de tipo com uma validação efetiva.

Um selo de tipo não altera o dado; a validação precisa inspecionar o valor recebido.
Atenção
cast serve para informar algo ao analisador estático quando você já tem uma justificativa externa para o tipo. Ele não deve ser usado como substituto para validar dados vindos de JSON, arquivos, rede ou usuário.
Considere que bruto veio de uma fonte externa e contém:
{"nome": 42, "quantidade": "muitas", "etiquetas": ["novo", 7]}
from typing import TypedDict, cast
class Produto(TypedDict):
nome: str
quantidade: int
etiquetas: list[str]
bruto: object = {
"nome": 42,
"quantidade": "muitas",
"etiquetas": ["novo", 7],
}
produto = cast(Produto, bruto)
print(produto["nome"].upper()) # falha em execução: 42 não tem upper()Depois do cast, o mypy passa a considerar produto["nome"] como str. Porém, o objeto original ainda guarda o inteiro 42. Ao chamar .upper(), o programa falha.
O cast também não cria um novo dicionário: produto e bruto apontam para o mesmo objeto.
isinstance(valor, dict) confirma apenas que o valor é um dicionário. Não confirma que as chaves obrigatórias existem nem que seus valores têm os tipos esperados. Do mesmo modo, isinstance(valor, list) não confirma o tipo de cada elemento.
Os dois testes abaixo podem passar mesmo para dados incompatíveis com Produto.
valor: object = {
"nome": 42,
"etiquetas": ["novo", 7],
}
print(isinstance(valor, dict)) # True
print(isinstance(valor["etiquetas"], list)) # True
# Ainda falta "quantidade"; nome não é str;
# e um elemento de etiquetas não é str.Atenção
Não use isinstance(valor, list[str]): tipos parametrizados não são validadores de execução. Também não use isinstance(valor, Produto): TypedDict descreve um contrato estático e não funciona como classe verificável nesse teste.
Primeiro, verifique contêineres concretos como dict e list; depois, inspecione separadamente a estrutura e os valores.
Qual alternativa, sozinha, realmente comprova que um valor externo satisfaz o contrato completo de Produto?

Passo 3 de 8
Rejeite uma raiz incompatível e chaves obrigatórias ausentes antes de extrair valores ainda não validados.
A função recebe object, portanto ainda não pode usar dado["nome"]. Primeiro, confirme que a raiz é um dicionário. Depois, confirme separadamente a presença de nome, quantidade e etiquetas.
Uma chave ausente é uma falha estrutural. Já uma chave presente com valor None passou apenas pela verificação de presença: seu valor ainda será validado em outra etapa. Assim, a fronteira produz ValueError previsível, em vez de deixar um KeyError acidental escapar.

Verificar a raiz e as chaves vem antes de consultar qualquer campo obrigatório.
Mesmo após isinstance(dado, dict), os valores armazenados no dicionário não ganharam os tipos do contrato. Por isso, extraia cada campo para uma variável anotada como object.
Neste caso, chaves extras são permitidas, mas ignoradas: a próxima etapa trabalhará somente com os três valores necessários. Ainda não valide str, int ou os elementos das etiquetas aqui.
def extrair_campos_obrigatorios(dado: object) -> tuple[object, object, object]:
if not isinstance(dado, dict):
raise ValueError("raiz: esperado um objeto JSON")
for campo in ("nome", "quantidade", "etiquetas"):
if campo not in dado:
raise ValueError(f"raiz.{campo}: campo obrigatório ausente")
# As chaves existem, mas seus valores continuam sem tipo comprovado.
nome: object = dado["nome"]
quantidade: object = dado["quantidade"]
etiquetas: object = dado["etiquetas"]
# Chaves extras não são extraídas nem transferidas adiante.
return nome, quantidade, etiquetasRelacione cada entrada ou situação com a verificação que deve tratá-la primeiro.
Toque em um item e depois no par correspondente.

Passo 4 de 8
Use verificações progressivas para transformar valores locais anotados como object em valores seguros para uso tipado.
Após validar a estrutura, os valores extraídos ainda são object. Portanto, não chame operações específicas nem construa o resultado final antes de estreitá-los.
Cada guarda que falha encerra aquele caminho com raise. Nos caminhos restantes, o mypy pode reconhecer o tipo confirmado por isinstance.
![Diagrama mostrando três valores genéricos passando por guardas de tipo: texto se torna str, número se torna int após excluir bool, e uma lista genérica tem cada elemento verificado antes de formar list[str].](https://cursa-json-routes.s3.amazonaws.com/learning-paths/pt/python/b730454e0225/level-12/tutorial-11/step-04/screen-01/item-02.webp)
Cada etapa produz uma garantia menor e mais específica: do valor externo genérico para um componente com tipo conhecido.
Atenção
Em Python, bool é subtipo de int. Logo, isinstance(True, int) é True. Se o contrato aceita quantidade inteira, mas não valores booleanos, teste e rejeite bool explicitamente antes de aceitar int.
Este trecho recebe os valores já extraídos da estrutura. Ele ainda não monta o Produto: apenas devolve componentes com tipos conhecidos.
def estreitar_campos(
nome_raw: object,
quantidade_raw: object,
etiquetas_raw: object,
) -> tuple[str, int, list[str]]:
if not isinstance(nome_raw, str):
raise ValueError("nome deve ser str")
nome = nome_raw
if isinstance(quantidade_raw, bool):
raise ValueError("quantidade não pode ser bool")
if not isinstance(quantidade_raw, int):
raise ValueError("quantidade deve ser int")
quantidade = quantidade_raw
if not isinstance(etiquetas_raw, list):
raise ValueError("etiquetas deve ser list")
etiquetas: list[str] = []
for indice, item in enumerate(etiquetas_raw):
etiqueta: object = item
if not isinstance(etiqueta, str):
raise ValueError(f"etiquetas[{indice}] deve ser str")
etiquetas.append(etiqueta)
return nome, quantidade, etiquetasDica
Mesmo depois de confirmar que etiquetas_raw é uma list, seus elementos ainda precisam ser tratados como object. A nova list[str] só recebe elementos que passaram pela verificação individual. Não use cast para declarar que a lista externa já é list[str].
Complete a condição antes da verificação de int:
if ________:
raise ValueError("quantidade não pode ser bool")
if not isinstance(quantidade_raw, int):
raise ValueError("quantidade deve ser int")A lista externa já foi confirmada como list, mas cada item ainda precisa ser validado:
etiquetas: list[str] = []
for indice, item in enumerate(etiquetas_raw):
etiqueta: object = item
if ________:
raise ValueError(f"etiquetas[{indice}] deve ser str")
etiquetas.append(etiqueta)
Passo 5 de 8
Aplique regras do domínio depois do estreitamento de tipos: normalize o nome, aceite quantidades não negativas e mantenha explícita a política para etiquetas.
Depois de confirmar os tipos, ainda falta decidir se os valores são aceitáveis para o domínio. Um str pode ser vazio ou conter apenas espaços; um int pode ser negativo. Essas situações são compatíveis com as anotações, mas podem violar o contrato de Produto.
Primeiro, o valor precisa ter o tipo esperado. Depois, precisa obedecer às regras definidas para o campo.

str e int descrevem a forma do valor; regras semânticas decidem se ele é aceito.
Exemplo
nome = " ": é str, mas será rejeitado após normalização.quantidade = -3: é int, mas será rejeitado pela regra de não negatividade.quantidade = 0: é int e é aceito pelo contrato deste caso.quantidade = "3": tem aparência numérica, mas é str; foi rejeitado antes, na etapa de tipo.Use strip() somente depois de já saber que nome é str. A normalização remove espaços das extremidades; em seguida, compare o resultado com a string vazia. Assim, um nome como " Caderno " é aceito como "Caderno", enquanto " " é rejeitado.
Considere que nome já foi estreitado para str em uma etapa anterior.
nome_normalizado = nome.strip()
if nome_normalizado == "":
raise ValueError("nome: não pode ficar vazio após normalização")Dica
A normalização preserva o fato de o valor ser texto. Ela não autoriza chamar strip() em um object ainda não verificado nem transforma valores de outros tipos em nomes válidos.
Para quantidade, a regra é quantidade >= 0: zero representa uma quantidade válida; valores negativos são rejeitados. Não há coerção implícita: "12" não vira 12.
Para etiquetas, uma lista vazia é aceita. A regra é que cada elemento existente seja str; ela não exige ao menos uma etiqueta.
Considere que quantidade já é um int não booleano e que cada etiqueta já foi confirmada como str.
if quantidade < 0:
raise ValueError("quantidade: deve ser não negativa")
# [] é válida. Se houver elementos, todos já devem ter sido verificados como str.
etiquetas_validadas: list[str] = []
for etiqueta in etiquetas:
if not isinstance(etiqueta, str):
raise ValueError("etiquetas: cada elemento deve ser str")
etiquetas_validadas.append(etiqueta)Atenção
Não use int(valor) para fazer "12" passar como quantidade neste contrato. Essa conversão mudaria a política de aceitação: aqui, a entrada deve já conter um inteiro válido, e não apenas um texto conversível.
A entrada nome = " " deve ser aceita porque seu tipo é str.
Qual valor de quantidade, já confirmado como int e não booleano, deve ser aceito pela regra deste caso?

Passo 6 de 8
Integre todas as verificações em uma função que separa a entrada externa de um Produto construído com valores validados.
A função validadora tem dois desfechos: ela interrompe o processamento com ValueError ao encontrar uma entrada inválida ou retorna um Produto construído no fim. Não devolva o dicionário recebido: monte um novo registro com nome, quantidade e uma nova lista de etiquetas já validadas.
A saída é criada a partir de componentes já estreitados, e não por uma afirmação sobre o contêiner externo.

O novo dicionário e a nova lista formam uma fronteira: campos extras e valores não verificados não atravessam.
import json
from typing import TypedDict
class Produto(TypedDict):
nome: str
quantidade: int
etiquetas: list[str]
def validar_produto(entrada: object) -> Produto:
if not isinstance(entrada, dict):
raise ValueError("raiz: esperado um objeto JSON")
for campo in ("nome", "quantidade", "etiquetas"):
if campo not in entrada:
raise ValueError(f"{campo}: campo obrigatório ausente")
nome_bruto: object = entrada["nome"]
quantidade_bruta: object = entrada["quantidade"]
etiquetas_brutas: object = entrada["etiquetas"]
if not isinstance(nome_bruto, str):
raise ValueError("nome: esperado str")
nome = nome_bruto.strip()
if not nome:
raise ValueError("nome: não pode ficar vazio")
if isinstance(quantidade_bruta, bool) or not isinstance(quantidade_bruta, int):
raise ValueError("quantidade: esperado int que não seja bool")
if quantidade_bruta < 0:
raise ValueError("quantidade: não pode ser negativa")
if not isinstance(etiquetas_brutas, list):
raise ValueError("etiquetas: esperado list")
etiquetas_validadas: list[str] = []
for indice, etiqueta_bruta in enumerate(etiquetas_brutas):
etiqueta: object = etiqueta_bruta
if not isinstance(etiqueta, str):
raise ValueError(f"etiquetas[{indice}]: esperado str")
etiquetas_validadas.append(etiqueta)
produto: Produto = {
"nome": nome,
"quantidade": quantidade_bruta,
"etiquetas": etiquetas_validadas,
}
return produto
texto_json = '{"nome": " Caderno ", "quantidade": 0, "etiquetas": ["papel"]}'
dado_externo: object = json.loads(texto_json)
produto = validar_produto(dado_externo)
print(produto)
print(produto["nome"].upper())No literal atribuído a produto: Produto, nome só chegou ali depois de ser confirmado como str e normalizado. quantidade_bruta só continua após a verificação de int e a exclusão de bool. Já etiquetas_validadas é uma list[str] nova, preenchida somente depois da inspeção de cada elemento.
A anotação no ponto de construção permite que o mypy confira as chaves e os tipos dos valores. Isso é diferente de usar cast(Produto, entrada), que apenas afirmaria um contrato sem criar nem verificar nada.
Dica
O consumidor pode usar produto["nome"] como str sem repetir a validação. Porém, Produto ainda é um dicionário comum: código posterior pode alterá-lo. A garantia obtida vale para o valor construído e retornado naquele momento.
No literal de produto: Produto, complete o valor para preservar a separação da lista externa:
"etiquetas": ____
Por que a função retorna um Produto confiável para o código consumidor sem copiar o dicionário bruto nem usar cast?
Escreva pelo menos 80 caracteres (0/80).

Passo 7 de 8
Use análise estática e testes de execução como evidências complementares para uma fronteira que transforma dados externos em Produto.
A fronteira já retorna Produto apenas depois de validar a entrada. Agora, verifique-a de duas formas:
mypy --strict analisa o código: compatibilidade entre argumentos, campos do TypedDict e retorno declarado.pytest executa exemplos: confirma que dados externos inválidos geram ValueError e que limites válidos são aceitos.Uma anotação int não expressa que o número deve ser não negativo. Por isso, mypy não rejeita uma quantidade negativa apenas pelo seu valor; esse comportamento precisa de testes em tempo de execução.
Observe onde cada evidência atua no fluxo de entrada.

mypy examina a consistência dos contratos no código; pytest exercita valores reais que atravessam a fronteira.
Faça as associações mais adequadas.
Toque em um item e depois no par correspondente.
Em uma pasta vazia, crie produto.py com a fronteira e consumidor.py com um uso válido. O parâmetro da fronteira permanece object: a desserialização não justifica afirmar uma estrutura antes da validação.
from typing import TypedDict
class Produto(TypedDict):
nome: str
quantidade: int
etiquetas: list[str]
def validar_produto(entrada: object) -> Produto:
if not isinstance(entrada, dict):
raise ValueError("raiz: esperado um objeto JSON")
for campo in ("nome", "quantidade", "etiquetas"):
if campo not in entrada:
raise ValueError(f"{campo}: campo obrigatório ausente")
nome_bruto: object = entrada["nome"]
quantidade_bruta: object = entrada["quantidade"]
etiquetas_brutas: object = entrada["etiquetas"]
if not isinstance(nome_bruto, str):
raise ValueError("nome: esperado str")
nome = nome_bruto.strip()
if not nome:
raise ValueError("nome: não pode ficar vazio")
if isinstance(quantidade_bruta, bool) or not isinstance(quantidade_bruta, int):
raise ValueError("quantidade: esperado int, sem bool")
if quantidade_bruta < 0:
raise ValueError("quantidade: não pode ser negativa")
if not isinstance(etiquetas_brutas, list):
raise ValueError("etiquetas: esperado list")
etiquetas: list[str] = []
for indice, etiqueta_bruta in enumerate(etiquetas_brutas):
if not isinstance(etiqueta_bruta, str):
raise ValueError(f"etiquetas[{indice}]: esperado str")
etiquetas.append(etiqueta_bruta)
return {
"nome": nome,
"quantidade": quantidade_bruta,
"etiquetas": etiquetas,
}import json
from produto import Produto, validar_produto
def carregar(texto: str) -> Produto:
externo: object = json.loads(texto)
return validar_produto(externo)
produto = carregar('{"nome": " Caneta ", "quantidade": 0, "etiquetas": []}')
print(produto["nome"].upper())
print(produto["quantidade"] + 1)Dica
Com mypy instalado no ambiente, execute:
python -m mypy --strict produto.py consumidor.py
O resultado esperado é sucesso sem erros. Isso sustenta que o consumidor recebe um Produto compatível; não demonstra que toda entrada externa será válida.
Crie test_produto.py. Os testes abaixo cobrem falhas estruturais, erros de tipo e regras semânticas. Também verificam dois limites aceitos: quantidade zero e lista vazia de etiquetas.
import json
import pytest
from produto import validar_produto
@pytest.mark.parametrize(
"entrada",
[
[],
{"quantidade": 1, "etiquetas": []},
{"nome": None, "quantidade": 1, "etiquetas": []},
{"nome": "A", "quantidade": "1", "etiquetas": []},
{"nome": "A", "quantidade": 1, "etiquetas": ["nova", 2]},
],
)
def test_rejeita_estrutura_ou_tipos_invalidos(entrada: object) -> None:
with pytest.raises(ValueError):
validar_produto(entrada)
@pytest.mark.parametrize(
"entrada",
[
{"nome": " ", "quantidade": 1, "etiquetas": []},
{"nome": "A", "quantidade": -1, "etiquetas": []},
{"nome": "A", "quantidade": True, "etiquetas": []},
],
)
def test_rejeita_regras_semanticas(entrada: object) -> None:
with pytest.raises(ValueError):
validar_produto(entrada)
def test_aceita_limites_e_normaliza_nome() -> None:
produto = validar_produto(
{"nome": " Caneta ", "quantidade": 0, "etiquetas": []}
)
assert produto == {
"nome": "Caneta",
"quantidade": 0,
"etiquetas": [],
}
def test_json_invalido_falha_antes_da_validacao() -> None:
with pytest.raises(json.JSONDecodeError):
json.loads('{"nome": "Caneta",}')Atenção
json.loads rejeita texto que não é JSON sintaticamente válido, como uma vírgula final indevida. Já validar_produto recebe um objeto desserializado e rejeita dados que violam o contrato, como {"quantidade": -1} ou uma raiz em lista.
Não capture JSONDecodeError como se fosse uma falha de regra do Produto: são etapas diferentes.
Dica
Na mesma pasta, execute:
python -m pytest -q
O resultado esperado é que todos os testes passem. Uma suíte verde é evidência para os casos escolhidos, não uma prova de ausência de defeitos fora deles.
Depois de executar os comandos no seu computador, relate o resultado de mypy e de pytest. Inclua um caso semanticamente inválido que mypy não rejeitaria apenas por analisar o tipo.
Escreva pelo menos 80 caracteres (0/80).
Resumo

Passo 8 de 8
Aplique a validação de um Produto, verifique-a localmente e consolide as garantias obtidas na fronteira de entrada.
A fronteira recebe dados que podem ter qualquer forma. O fluxo completo é: desserializar o JSON, guardar o resultado como object, verificar a estrutura, estreitar cada campo, aplicar regras semânticas e criar um novo Produto.
O consumidor recebe somente esse novo registro quando todas as etapas terminam sem erro. Caso contrário, a função encerra com ValueError previsível.
Cada camada elimina uma classe diferente de entrada inadequada antes da construção do retorno.

O contrato de saída só existe depois de estrutura, tipos e regras terem sido verificados.
No seu computador, crie um arquivo chamado produto.py com o código abaixo. Complete o trecho marcado por TODO: depois de normalizar o nome, rejeite um nome vazio com ValueError, sem mudar o TypedDict nem usar cast.
Depois, crie test_produto.py com os testes apresentados. Eles incluem uma entrada válida e uma entrada estruturalmente válida, mas semanticamente inválida.
import json
from typing import TypedDict
class Produto(TypedDict):
nome: str
quantidade: int
etiquetas: list[str]
def validar_produto(entrada: object) -> Produto:
if not isinstance(entrada, dict):
raise ValueError("raiz: esperado um objeto")
registro: dict[object, object] = entrada
for campo in ("nome", "quantidade", "etiquetas"):
if campo not in registro:
raise ValueError(f"{campo}: campo obrigatório ausente")
nome_bruto: object = registro["nome"]
quantidade_bruta: object = registro["quantidade"]
etiquetas_brutas: object = registro["etiquetas"]
if not isinstance(nome_bruto, str):
raise ValueError("nome: esperado str")
if not isinstance(quantidade_bruta, int) or isinstance(quantidade_bruta, bool):
raise ValueError("quantidade: esperado int, exceto bool")
if not isinstance(etiquetas_brutas, list):
raise ValueError("etiquetas: esperado list")
etiquetas: list[str] = []
for indice, etiqueta_bruta in enumerate(etiquetas_brutas):
etiqueta: object = etiqueta_bruta
if not isinstance(etiqueta, str):
raise ValueError(f"etiquetas[{indice}]: esperado str")
etiquetas.append(etiqueta)
nome = nome_bruto.strip()
# TODO: rejeite nome == "" com ValueError.
if quantidade_bruta < 0:
raise ValueError("quantidade: deve ser não negativa")
return {
"nome": nome,
"quantidade": quantidade_bruta,
"etiquetas": etiquetas,
}
def carregar_produto(texto: str) -> Produto:
bruto: object = json.loads(texto)
return validar_produto(bruto)import pytest
from produto import carregar_produto
def test_aceita_e_normaliza_um_produto_valido() -> None:
produto = carregar_produto(
'{"nome": " Café ", "quantidade": 0, "etiquetas": []}'
)
assert produto == {
"nome": "Café",
"quantidade": 0,
"etiquetas": [],
}
def test_rejeita_nome_vazio_apos_normalizacao() -> None:
with pytest.raises(ValueError, match="nome"):
carregar_produto(
'{"nome": " ", "quantidade": 2, "etiquetas": ["bebida"]}'
)Com o ambiente que contém mypy e pytest, execute:
python -m mypy --strict produto.py test_produto.py
python -m pytest -q
O mypy deve confirmar a consistência das anotações analisadas. O pytest deve aprovar o caso válido — inclusive quantidade zero e etiquetas vazias — e confirmar que o nome formado apenas por espaços é rejeitado.
Relate: (1) a condição que você adicionou; (2) o resultado da entrada válida; (3) a rejeição observada para o nome vazio; e (4) o resultado de mypy e pytest. Por que trocar essa condição por cast(Produto, ...) não preservaria o mesmo comportamento?
Escreva pelo menos 180 caracteres (0/180).
Resumo
Use este checklist ao receber dados externos para um registro tipado.
Parabéns! Você concluiu: Converter dados externos em valores validados e tipados
Você concluiu este nível!
Agora você vai iniciar: Concorrência e programação assíncrona
Escolher entre threads, processos e asyncioAo concluir, você será capaz de escolher um modelo de concorrência conforme o tipo de tarefa, as necessidades de compartilhamento de dados e as características do interpretador.Milhares de cursos online em vídeo, ebooks e áudiobooks.
Para testar seus conhecimentos no decorrer dos cursos online
Gerado diretamente na galeria de fotos do seu celular e enviado ao seu e-mail
Baixe nosso aplicativo pelo QR Code ou pelos links abaixo:.
+ de 10 milhões
de alunos
Certificado grátis e
válido em todo o Brasil
60 mil exercícios
gratuitos
4,8/5 classificação
nas lojas de apps
Cursos gratuitos em
vídeo, ebooks e audiobooks