JSON in Python
Genera dataclass Python da JSON
Input JSON
Output Python
Cos'è la conversione da JSON a dataclass Python?
La conversione da JSON a dataclass Python prende un oggetto JSON grezzo e produce un insieme di definizioni di dataclass Python con annotazioni di tipo accurate. Il modulo dataclasses di Python, introdotto in PEP 557 (Python 3.7), genera i metodi __init__, __repr__ e __eq__ a partire dai campi della classe annotati. Quando lavori con API JSON, file di configurazione o code di messaggi, le dataclass danno ai tuoi dati una struttura tipizzata che editor e type checker come mypy possono verificare durante lo sviluppo.
json.loads() di Python restituisce dizionari e liste semplici. Funzionano, ma non hanno informazioni sui tipi: una chiave scritta male restituisce None invece di sollevare un errore, e l'editor non può completare automaticamente i nomi dei campi. Le dataclass risolvono questo problema mappando ogni chiave JSON su un campo con nome e tipo. Gli oggetti JSON annidati diventano definizioni di dataclass separate, gli array diventano annotazioni List[T], e i valori null diventano Optional[T] con un valore predefinito di None.
Scrivere queste definizioni a mano è un lavoro meccanico. Devi leggere il JSON, dedurre il tipo di ogni campo dal suo valore, convertire le chiavi da camelCase o snake_case alle convenzioni Python, e gestire casi particolari come campi nullable e array di tipo misto. Un convertitore fa tutto questo in pochi millisecondi. Incolli il JSON, ottieni codice dataclass corretto e vai avanti.
Perché usare un convertitore da JSON a Python?
Tradurre strutture JSON in definizioni di classi Python a mano significa indovinare i tipi dai dati di esempio, riordinare i campi in modo che quelli obbligatori vengano prima di quelli opzionali, e aggiornare tutto quando l'API cambia. Un convertitore elimina questa attrito.
Casi d'uso di JSON in Python
Mappatura dei tipi da JSON a Python
Ogni valore JSON si mappa a una specifica annotazione di tipo Python. La tabella seguente mostra come il convertitore traduce ogni tipo JSON, con la sintassi del modulo typing (Python 3.7+) e la sintassi built-in disponibile da Python 3.10 in poi.
| Tipo JSON | Esempio | 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] |
Riferimento al decoratore Dataclass
Il decoratore @dataclass accetta diversi parametri che cambiano il comportamento della classe generata. Questo riferimento copre le opzioni più rilevanti quando si lavora con dati derivati da JSON.
| Decoratore / Campo | Comportamento | Usare quando |
|---|---|---|
| @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 offre tre metodi comuni per definire strutture tipizzate a partire da JSON. Ognuno si adatta a un caso d'uso diverso. Le dataclass sono l'opzione della libreria standard senza dipendenze esterne. Pydantic aggiunge la validazione a runtime. TypedDict annota dizionari semplici senza creare una nuova classe.
Esempi di codice
Questi esempi mostrano come usare le dataclass generate in Python, come produrle programmaticamente da JavaScript, e come usare approcci alternativi come Pydantic e strumenti 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]