Python e JSON formam uma dupla natural.
Seja construindo uma API REST com FastAPI
ou Django,
processando pipelines de dados, ou apenas lendo um arquivo de configuração, você vai trabalhar com JSON constantemente.
A boa notícia: a biblioteca padrão do Python tem tudo que você precisa no
módulo json.
Sem necessidade de pip install.
As Quatro Funções que Você Realmente Usa
O módulo json oferece quatro funções para o dia a dia:
json.loads(str)— analisa uma string JSON em um objeto Pythonjson.dumps(obj)— converte um objeto Python em uma string JSONjson.load(file)— analisa JSON diretamente de um objeto arquivojson.dump(obj, file)— escreve um objeto Python como JSON em um arquivo
O s em loads / dumps significa string.
As que não têm o s trabalham com objetos de arquivo. Fácil de lembrar quando você conhece a regra.
json.loads() — Analisando uma String JSON
import json
json_string = '{"name": "Alice", "age": 30, "active": true, "score": 98.5}'
user = json.loads(json_string)
print(user["name"]) # Alice
print(user["age"]) # 30
print(user["active"]) # True
print(type(user)) # <class 'dict'>Observe o mapeamento de tipos: JSON true vira Python True,
JSON false vira Python False, JSON null vira Python None.
Objetos JSON viram Python dict, arrays JSON viram Python list.
json.dumps() — Serializando para uma String JSON
import json
user = {
"name": "Bob",
"age": 25,
"roles": ["admin", "editor"],
"active": True,
"extra": None
}
# Compacto (bom para transmissão em rede)
compact = json.dumps(user)
print(compact)
# {"name": "Bob", "age": 25, "roles": ["admin", "editor"], "active": true, "extra": null}
# Formatado (bom para logs e inspeção humana)
pretty = json.dumps(user, indent=2)
print(pretty)
# {
# "name": "Bob",
# "age": 25,
# "roles": [
# "admin",
# "editor"
# ],
# "active": true,
# "extra": null
# }Observe o mapeamento inverso de tipos: Python True → JSON true,
Python None → JSON null. O Python lida com isso automaticamente.
Lendo JSON de um Arquivo
Este é provavelmente o caso de uso mais comum — ler um arquivo de configuração ou dados na inicialização:
import json
# Lê e analisa em uma etapa
with open("config.json", "r", encoding="utf-8") as f:
config = json.load(f)
print(config["database"]["host"]) # localhost
print(config["database"]["port"]) # 5432Sempre especifique encoding="utf-8" ao abrir arquivos JSON. O JSON é especificado como UTF-8
pela RFC 8259,
e omiti-lo pode causar problemas no Windows, onde o encoding padrão às vezes é cp1252.
Escrevendo JSON em um Arquivo
import json
results = {
"timestamp": "2024-01-15T09:30:00Z",
"total": 1523,
"processed": 1521,
"failed": 2,
"errors": [
{"id": 42, "reason": "missing field"},
{"id": 99, "reason": "invalid format"}
]
}
with open("results.json", "w", encoding="utf-8") as f:
json.dump(results, f, indent=2)
print("Results saved to results.json")Tratando Erros Corretamente
json.loads() lança
json.JSONDecodeError
(uma subclasse de ValueError) quando a entrada não é um JSON válido. Sempre trate isso ao analisar
dados que você não controla:
import json
def safe_parse(json_str):
try:
return json.loads(json_str)
except json.JSONDecodeError as e:
print(f"Invalid JSON at line {e.lineno}, column {e.colno}: {e.msg}")
return None
data = safe_parse('{"name": "Alice"}') # funciona normalmente
bad = safe_parse('not json at all') # imprime erro, retorna None
also_bad = safe_parse('{"key": }') # imprime erro com informação de posiçãoJSONDecodeError fornece a linha e coluna exatas onde a análise falhou,
o que é útil ao depurar arquivos JSON grandes.
Opções Úteis do dumps()
import json
data = {
"z_key": 1,
"a_key": 2,
"price": 9.999999999
}
# Ordenar chaves alfabeticamente (ótimo para saída reproduzível / diffs)
print(json.dumps(data, sort_keys=True, indent=2))
# {
# "a_key": 2,
# "price": 9.999999999,
# "z_key": 1
# }
# Garantir que caracteres não-ASCII sejam preservados (padrão: escapados para \uXXXX)
data2 = {"city": "Münich", "greeting": "こんにちは"}
print(json.dumps(data2, ensure_ascii=False))
# {"city": "Münich", "greeting": "こんにちは"}
# Com ensure_ascii=True (padrão):
print(json.dumps(data2))
# {"city": "M\u00fcnich", "greeting": "\u3053\u3093\u306b\u3061\u306f"}ensure_ascii=False é algo que sempre adiciono ao escrever arquivos JSON que
contêm texto não-ASCII. A versão escapada é tecnicamente JSON válido, mas muito mais difícil de ler em um editor de texto.
Serializando Objetos Personalizados
Por padrão, json.dumps() não consegue serializar instâncias de classes personalizadas ou objetos
datetime.
Você tem duas opções: criar uma subclasse de
json.JSONEncoder,
ou converter para um dict primeiro:
import json
from datetime import datetime, date
# Opção 1: classe de encoder personalizada
class AppEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, (datetime, date)):
return obj.isoformat()
return super().default(obj)
data = {"name": "Alice", "created_at": datetime(2024, 1, 15, 9, 30)}
print(json.dumps(data, cls=AppEncoder, indent=2))
# {
# "name": "Alice",
# "created_at": "2024-01-15T09:30:00"
# }
# Opção 2: parâmetro default= (mais simples para conversões pontuais)
print(json.dumps(data, default=str, indent=2)) # converte qualquer tipo desconhecido para strUm Padrão Prático: Carregando Arquivo de Configuração
Aqui está um padrão do mundo real que uso em quase todo projeto Python — um carregador de configuração que lê um arquivo de configuração JSON com valores padrão sensatos:
import json
import os
from pathlib import Path
DEFAULTS = {
"database": {"host": "localhost", "port": 5432},
"debug": False,
"log_level": "INFO"
}
def load_config(path="config.json"):
config = DEFAULTS.copy()
config_path = Path(path)
if config_path.exists():
with open(config_path, "r", encoding="utf-8") as f:
try:
user_config = json.load(f)
# Mesclagem profunda: configurações do usuário substituem os padrões
for key, value in user_config.items():
if isinstance(value, dict) and key in config:
config[key].update(value)
else:
config[key] = value
except json.JSONDecodeError as e:
print(f"Warning: config.json is invalid ({e.msg}), using defaults")
return config
config = load_config()
print(config["database"]["host"]) # localhost (ou valor substituído)Conclusão
O módulo json do Python cobre tudo que você precisa sem dependências externas.
As regras principais: use loads()/dumps() para strings, load()/dump()
para arquivos, sempre trate JSONDecodeError ao analisar dados externos, e adicione
ensure_ascii=False quando seus dados contiverem caracteres não-latinos.
Para depurar dados JSON, o Formatador JSON e o
Validador JSON podem economizar muito tempo.