JSON a Python
Genera Python dataclasses desde JSON
Entrada JSON
Salida Python
¿Qué es la conversión de JSON a Python dataclass?
La conversión de JSON a Python dataclass toma un objeto JSON en bruto y genera un conjunto de definiciones de Python dataclass con anotaciones de tipo precisas. El módulo dataclasses de Python, introducido en el PEP 557 (Python 3.7), genera los métodos __init__, __repr__ y __eq__ a partir de los campos anotados de la clase. Cuando trabajas con APIs JSON, archivos de configuración o colas de mensajes, los dataclasses dan a tus datos una estructura tipada que los editores y los verificadores de tipos como mypy pueden validar en tiempo de desarrollo.
El método json.loads() de Python devuelve dicts y listas simples. Funcionan, pero no tienen información de tipos: una clave mal escrita devuelve None en lugar de lanzar un error, y el editor no puede autocompletar los nombres de los campos. Los dataclasses resuelven esto mapeando cada clave JSON a un campo con nombre y tipo. Los objetos JSON anidados se convierten en definiciones de dataclass separadas, los arrays se convierten en anotaciones List[T] y los valores nulos en Optional[T] con un valor por defecto de None.
Escribir estas definiciones a mano es un trabajo mecánico. Hay que leer el JSON, deducir el tipo de cada campo a partir de su valor, convertir las claves de camelCase o snake_case a las convenciones de Python, y gestionar casos extremos como campos anulables y arrays de tipos mixtos. Un conversor hace todo esto en milisegundos. Pegas el JSON, obtienes código de dataclass correcto y puedes seguir adelante.
¿Por qué usar un conversor de JSON a Python?
Traducir estructuras JSON a definiciones de clases Python a mano implica adivinar tipos a partir de datos de ejemplo, reordenar campos para que los obligatorios vayan antes que los opcionales, y actualizar todo cuando cambia la API. Un conversor elimina esa fricción.
Casos de uso de JSON a Python
Mapeo de tipos JSON a Python
Cada valor JSON se mapea a una anotación de tipo Python específica. La tabla siguiente muestra cómo el conversor traduce cada tipo JSON, tanto con la sintaxis del módulo typing (Python 3.7+) como con la sintaxis integrada disponible desde Python 3.10 en adelante.
| Tipo JSON | Ejemplo | Python (typing) | Python 3.10+ |
|---|---|---|---|
| string | "hello" | str | str |
| number (integer) | 42 | int | int |
| number (float) | 3.14 | float | float |
| boolean | true | bool | bool |
| null | null | Optional[str] | str | None |
| object | {"k": "v"} | @dataclass class | nested model |
| array of strings | ["a", "b"] | List[str] | list[str] |
| array of objects | [{"id": 1}] | List[Item] | list[Item] |
| mixed array | [1, "a"] | List[Any] | list[Any] |
Referencia del decorador dataclass
El decorador @dataclass acepta varios parámetros que cambian el comportamiento de la clase generada. Esta referencia cubre las opciones más relevantes al trabajar con datos derivados de JSON.
| Decorador / Campo | Comportamiento | Cuándo usarlo |
|---|---|---|
| @dataclass | Generates __init__, __repr__, __eq__ from field annotations | Standard dataclasses |
| @dataclass(frozen=True) | Makes instances immutable (hashable, no attribute reassignment) | Config objects, dict keys |
| @dataclass(slots=True) | Uses __slots__ for lower memory and faster attribute access | Python 3.10+, large datasets |
| @dataclass(kw_only=True) | All fields require keyword arguments in __init__ | Python 3.10+, many fields |
| field(default_factory=list) | Sets a mutable default without sharing state between instances | List/dict/set defaults |
dataclass vs Pydantic vs TypedDict
Python tiene tres formas habituales de definir estructuras tipadas a partir de JSON. Cada una encaja en un caso de uso diferente. Los dataclasses son la opción de la biblioteca estándar sin dependencias externas. Pydantic añade validación en tiempo de ejecución. TypedDict anota dicts simples sin crear una clase nueva.
Ejemplos de código
Estos ejemplos muestran cómo usar los dataclasses generados en Python, cómo producirlos mediante programación desde JavaScript y cómo usar alternativas como Pydantic y herramientas CLI.
from dataclasses import dataclass
from typing import List, Optional
import json
@dataclass
class Address:
street: str
city: str
zip: str
@dataclass
class User:
id: int
name: str
email: str
active: bool
score: float
address: Address
tags: List[str]
metadata: Optional[str] = None
raw = '{"id":1,"name":"Alice","email":"alice@example.com","active":true,"score":98.5,"address":{"street":"123 Main St","city":"Springfield","zip":"12345"},"tags":["admin","user"],"metadata":null}'
data = json.loads(raw)
# Reconstruct nested objects manually
addr = Address(**data["address"])
user = User(**{**data, "address": addr})
print(user.name) # -> Alice
print(user.address) # -> Address(street='123 Main St', city='Springfield', zip='12345')// Minimal JSON-to-Python-dataclass generator in JS
function jsonToPython(obj, name = "Root") {
const classes = [];
function infer(val, fieldName) {
if (val === null) return "Optional[str]";
if (typeof val === "string") return "str";
if (typeof val === "number") return Number.isInteger(val) ? "int" : "float";
if (typeof val === "boolean") return "bool";
if (Array.isArray(val)) {
const first = val.find(v => v !== null);
return first ? `List[${infer(first, fieldName + "Item")}]` : "List[Any]";
}
if (typeof val === "object") {
const clsName = fieldName.charAt(0).toUpperCase() + fieldName.slice(1);
build(val, clsName);
return clsName;
}
return "Any";
}
function build(obj, cls) {
const fields = Object.entries(obj).map(([k, v]) => ` ${k}: ${infer(v, k)}`);
classes.push(`@dataclass\nclass ${cls}:\n${fields.join("\n")}`);
}
build(obj, name);
return classes.join("\n\n");
}
const data = { id: 1, name: "Alice", scores: [98, 85] };
console.log(jsonToPython(data, "User"));
// @dataclass
// class User:
// id: int
// name: str
// scores: List[int]from pydantic import BaseModel
from typing import List, Optional
class Address(BaseModel):
street: str
city: str
zip: str
class User(BaseModel):
id: int
name: str
email: str
active: bool
score: float
address: Address
tags: List[str]
metadata: Optional[str] = None
# Pydantic parses and validates JSON in one step
raw = '{"id":1,"name":"Alice","email":"alice@example.com","active":true,"score":98.5,"address":{"street":"123 Main St","city":"Springfield","zip":"12345"},"tags":["admin","user"],"metadata":null}'
user = User.model_validate_json(raw)
print(user.name) # -> Alice
print(user.model_dump_json()) # -> re-serializes to JSON# Install the generator
pip install datamodel-code-generator
# Generate dataclasses from a JSON file
datamodel-codegen --input data.json --output models.py --output-model-type dataclasses.dataclass
# Generate Pydantic models instead
datamodel-codegen --input data.json --output models.py
# From a JSON string via stdin
echo '{"id": 1, "name": "Alice", "tags": ["admin"]}' | \
datamodel-codegen --output-model-type dataclasses.dataclass
# Output:
# @dataclass
# class Model:
# id: int
# name: str
# tags: List[str]