← Python na prática
08 / 10 · 50 MIN

JSON e iteradores com contratos de dados

Valida significado, identidade e consumo dos dados antes de publicar resultados de uma automação.

Separar parsing de aceitação

Um decoder conhece sintaxe e conversões; não conhece as regras do teu serviço. Um JSON que produz um dicionário pode conter nomes repetidos que já foram reduzidos ao último valor. Se o contrato proíbe repetição, verifica os pares durante o decoding, por exemplo com object_pairs_hook, antes de perder essa informação. Depois valida campos obrigatórios, tipos, limites e relações entre valores. bool é subclasse de int, pelo que isinstance(value, int) aceita True; explicita se isso é permitido. Define também limites de entrada antes da alocação do documento. Rejeitar um milhão de registos depois de os carregar não limita o custo inicial.

Preservar significado numérico

Para um montante decimal, parse_float=Decimal permite construir a partir do token textual sem passar primeiro por float. Isso não define por si só moeda, escala, arredondamento ou limites. Confirma finitude: Decimal também representa NaN e infinidades. O decoder json aceita certas constantes não finitas por defeito; parse_constant pode rejeitá-las. Mas amount="NaN" é uma string e não passa por esse tratamento como constante numérica. Na saída, allow_nan=False trata valores float especiais durante serialização. Não confundas essas opções nem assumas que uma conversão válida torna todos os valores elegíveis para cálculo financeiro.

Acordar a representação completa

Produtor e consumidor precisam do mesmo contrato de formato. ensure_ascii pode representar Évora com um escape sem remover o acento; isso é diferente de converter um Decimal para string com default=str, que altera o tipo JSON entregue. Chaves de objetos JSON são texto: identidades Python 7 e "7" precisam de um modelo sem colisões se representam entidades distintas. Finalmente, dois dump consecutivos não criam automaticamente um array nem um protocolo de múltiplos documentos. Escolhe um documento único ou framing explicitamente suportado por ambos os lados. Testa o round trip e os tipos recebidos, não apenas a aparência do ficheiro.

Consumir sem perder a fronteira de entrega

Um iterador guarda estado de consumo. Contar linhas com sum pode esgotar exatamente o objeto que pretendias percorrer depois. Se precisas de duas passagens, decide entre recriar a fonte, guardar dados limitados ou outra estratégia com custos conhecidos. Para emparelhar IDs e montantes, zip normal termina no mais curto; strict=True deteta comprimentos diferentes quando a iteração chega a essa diferença. Como a avaliação é gradual, operações anteriores do ciclo podem já ter produzido efeitos. Valida integralmente antes da publicação quando o contrato exige um lote completo, usando staging ou um protocolo transacional compatível com o volume e o consumidor.

Gerir retenção e vida dos recursos

A interface lazy não garante memória constante nem recursos abertos. Em tee, um consumidor muito atrasado pode obrigar à retenção de muitos valores; os iteradores resultantes também não são uma solução automática para consumo concorrente entre threads. Uma expressão geradora devolvida dentro de with open pode tentar ler só depois do fecho do ficheiro. Define quem abre, quem consome e quem fecha. A limpeza deve preservar a falha: um return no finally pode mascarar a exceção e transformar leitura falhada em sucesso vazio. Os ensaios precisam de observar valores, exceções e efeitos já produzidos, incluindo fim prematuro e dados parciais.

import json

def unique_names(pairs):
    result = {}
    for name, value in pairs:
        if name in result:
            raise ValueError("repeated field: " + name)
        result[name] = value
    return result

payload = '{"batch":"B-42","limit":12,"limit":24}'
try:
    json.loads(payload, object_pairs_hook=unique_names)
except ValueError as exc:
    print(str(exc))
NA PRÁTICA

Exercício original: o objeto de configuração de B-42 apresenta limit duas vezes. O hook rejeita o segundo nome em vez de escolher silenciosamente um valor. Este ensaio não valida um schema completo: acrescenta separadamente campos obrigatórios, tipos, finitude e limites antes de aceitar uma configuração.

Armadilhas comuns

Tratar loads como schema validator; validar duplicados depois de dict; converter precisão em float por conveniência; reutilizar iteradores esgotados; assumir que strict faz rollback; esconder erros no finally.

Tópicos relacionados: Funções pequenas, contratos claros · Erros e ficheiros com contexto · Precisão, dados externos e tempo · Automação observável e repetível

Leva esta ideia contigo

Valida antes de perder informação e antes de publicar efeitos; tipos, limites, identidade e vida dos recursos fazem parte do contrato.

Criar conta

Referência: Python3.14: JSON encoder and decoder · Python 3.14; DR Python 2026.3

Python® é uma marca registada de Python Software Foundation. A dr.pt é uma plataforma de preparação independente e não está afiliada, associada, patrocinada, autorizada nem aprovada por Python Software Foundation. Os conteúdos e as perguntas são originais, não são perguntas oficiais de exame, e concluir os nossos testes não atribui nem garante qualquer certificação. Os nomes são usados apenas para identificar o tema. Todas as outras marcas pertencem aos respetivos titulares.