Skip to content
Torna al blog
Tutorial

Da JSON a Python: dataclass, Pydantic e TypedDict (2026)

Converti JSON in classi Python online: dataclass, Pydantic v2 o TypedDict, tipizzazione Optional, alias camelCase e insidie da evitare. Gratis nel browser.

12 min di lettura

Da JSON a Python: dataclass, Pydantic e TypedDict (2026)

Incolla il tuo JSON nel convertitore da JSON a Python e copia le classi che genera. È la via rapida per trasformare JSON in Python: niente da installare, niente da caricare, tutto gira nel tuo browser. Per un modello una tantum o un’occhiata veloce a una risposta di API che non conosci, hai finito in pochi secondi.

Il problema più difficile è quello che un convertitore non può risolvere al posto tuo. Deduce i tipi corretti, ma non può prendere la decisione che conta di più: quale dei tre output vuoi davvero. Un dataclass, un BaseModel di Pydantic v2 e un TypedDict possono descrivere esattamente lo stesso JSON, eppure differiscono per solidità della type-safety, comportamento a runtime e modo in cui ci carichi i dati. Scegli male e finisci per trascinarti dietro la dipendenza da Pydantic per nulla, oppure dai per scontato che un dataclass validi il tuo input quando non lo fa affatto.

Questa guida copre la matrice decisionale per tutti e tre, come il convertitore deduce i tipi, la gestione del camelCase in ciascuna modalità, come effettuare il parsing del JSON con la classe che generi (compresa la trappola dell’annidamento che frega tutti), Pydantic v2 contro v1 e i casi limite che vale la pena conoscere prima di fidarti dell’output.

Come convertire JSON in Python

Convertire JSON in Python richiede tre passaggi:

  1. Incolla il tuo JSON. Trascina un oggetto, un array o una risposta di API grezza nella casella di input. La conversione parte all’istante e interamente lato client.
  2. Scegli dataclass, Pydantic o TypedDict. Usa il selettore Output per cambiare stile e rinomina il Root predefinito in qualcosa di significativo come User o ApiResponse.
  3. Copia o scarica. Prendi il Python generato con un clic e metti models.py direttamente nel tuo progetto.

Questo è l’intero flusso. Se il tuo input è minificato o non sei sicuro che sia valido, passalo prima in un formattatore JSON così il convertitore ha del JSON pulito e ben formato da leggere. Il resto di questa guida spiega l’output, così puoi sistemare i casi che uno strumento non è in grado di dedurre da solo.

Come i tipi JSON si mappano su Python

Ogni valore JSON ha una controparte in Python, e la corrispondenza è diretta:

Valore JSONTipo Python
"text"str
42int (precisione arbitraria, nessun overflow)
3.14, 2e3float
true / falsebool
nullOptional[T] / Optional[Any]
[1, 2, 3]List[T]
{ ... }una classe con nome

Prendi un tipico payload REST:

{ "id": 101, "name": "Ada Lovelace", "email": "ada@example.com", "active": true, "roles": ["admin", "user"] }

In modalità dataclass il convertitore produce una classe pronta all’uso:

from dataclasses import dataclass
from typing import List


@dataclass
class Root:
    id: int
    name: str
    email: str
    active: bool
    roles: List[str]

Una sfumatura distingue Python dagli altri. Il suo int ha precisione arbitraria, quindi uno snowflake di Discord o qualsiasi ID oltre 2^53 resta un semplice int senza perdite. JavaScript perderebbe precisione sullo stesso valore, e Rust ti costringerebbe a scegliere tra i64, u64 e f64. Solo un token scritto con un punto decimale o un esponente viene dedotto come float. Un campo che è sempre e solo null non può essere tipizzato dal solo campione, quindi ripiega su Optional[Any]; incolla un payload rappresentativo con un valore reale per ottenere qualcosa di più preciso di Any.

dataclass vs Pydantic v2 vs TypedDict — quale usare?

Questa è la scelta che il convertitore rimette a te, ed è il punto centrale di questa guida. In breve: opta per un dataclass quando vuoi un contenitore di dati interno a zero dipendenze, Pydantic v2 quando effettui il parsing o la validazione di input non affidabili, e TypedDict quando ti servono solo suggerimenti di tipo statici su dict che hai già.

DimensionedataclassPydantic v2TypedDict
DipendenzaLibreria standardpip install pydanticLibreria standard (typing)
Validazione a runtimeNoSì — valida e converteNo — solo suggerimenti
Costo a runtimeLeggero (oggetto reale)Un po’ (validazione)Zero (è un dict)
Parsing automatico annidatoNo, manualeSì, model_validate è ricorsivoNo, è un dict
Alias camelCaseMantiene la chiave originaleField(alias=...)Sintassi funzionale
Ideale perStrutture interneRisposte di API, webhook, configTipizzare codice dict legacy

I tre target sembrano quasi identici per una forma piccola come {"id": 101, "name": "Ada Lovelace", "active": true}. Un dataclass da JSON a Python ti dà un oggetto della libreria standard:

from dataclasses import dataclass


@dataclass
class Root:
    id: int
    name: str
    active: bool

La versione da JSON a Pydantic mette al suo posto BaseModel, che sembra simile ma si guadagna il posto a runtime:

from pydantic import BaseModel


class Root(BaseModel):
    id: int
    name: str
    active: bool

E un TypedDict Python da JSON descrive la forma di un semplice dict senza allocare nulla di nuovo:

from typing import TypedDict


class Root(TypedDict):
    id: int
    name: str
    active: bool

Stessi campi, tre contratti molto diversi. Il valore di generare tutti e tre da un unico campione è che puoi alternarli nello strumento e abbinare la modalità al compito: Pydantic quando fai il parsing di dati che non controlli, un dataclass quando i dati sono interni, e TypedDict quando vuoi solo che mypy capisca un dict che già passi in giro.

Come il convertitore deduce le classi

Tre regole coprono quasi tutto ciò che gli dai in pasto: una classe per ogni forma di oggetto, unione chiave per chiave per gli array, e una gestione attenta dei valori mancanti.

Deduzione strutturale: una classe con nome per ogni oggetto

Ogni forma di oggetto distinta diventa la propria classe con nome. Gli oggetti annidati non vengono incorporati in linea; vengono estratti in definizioni separate e referenziate:

{ "repo": "pydantic", "owner": { "login": "samuelcolvin", "id": 100 } }
from dataclasses import dataclass


@dataclass
class Owner:
    login: str
    id: int


@dataclass
class Root:
    repo: str
    owner: Owner

L’owner annidato diventa la sua classe Owner, referenziata dal campo. Nota l’ordine: la classe figlia viene emessa prima del genitore che la usa, così il modulo funziona senza from __future__ import annotations. Anche le forme identiche vengono deduplicate, quindi due campi con la stessa struttura condividono un’unica classe invece di produrre copie.

Unione degli array e campi Optional

Quando passi un array di oggetti, il convertitore li unisce chiave per chiave in un unico tipo di elemento. Una chiave presente in alcuni elementi ma assente in altri diventa Optional:

{ "users": [{ "id": 1, "nick": "x" }, { "id": 2 }] }
from typing import List, Optional, TypedDict


class User(TypedDict):
    id: int
    nick: Optional[str]


class Root(TypedDict):
    users: List[User]

id compare in ogni elemento, quindi resta obbligatorio. nick è assente dal secondo utente, quindi diventa Optional[str]. È esattamente per questo che un singolo oggetto è un campione debole: lo strumento può marcare un campo come Optional solo quando vede davvero la chiave mancare da qualche parte. Dagli in pasto un array rappresentativo e la deduzione rispecchierà la forma reale.

Optional, None e array vuoti

Alcuni valori non portano con sé alcun tipo, e il convertitore è onesto al riguardo. Una chiave mancante da alcuni elementi dell’array diventa Optional[T]. Un campo che è sempre e solo null diventa Optional[Any], perché il null di JSON da solo non ti dice nulla sul tipo previsto. Un array vuoto o con tipi di elemento misti ripiega su List[Any]. Nessuno di questi è un bug; è lo strumento che si rifiuta di tirare a indovinare. Sostituisci ogni Any con un tipo concreto non appena hai un campione che ne mostra uno, e ricorda che l’int a precisione arbitraria di Python significa che un ID grande non ti costringe mai a un tipo numerico più ampio, come invece accadrebbe in Rust o JavaScript.

Gestire le chiavi camelCase in ciascuna modalità

Le chiavi JSON sono spesso in camelCase mentre i campi Python idiomatici sono in snake_case. Qui non c’è un’unica risposta giusta, quindi ogni modalità la risolve in modo diverso, e vale la pena capire la differenza prima di copiare l’output.

dataclass. Un dataclass non ha alcun meccanismo di alias integrato. Per mantenere funzionante Root(**data), il convertitore mantiene la chiave originale come nome del campo ogni volta che è un identificatore Python valido, quindi publicRepos resta publicRepos. Forzarlo a snake_case romperebbe **data con un TypeError.

Pydantic v2. Qui ottieni il risultato idiomatico. I campi vengono rinominati in snake_case con un Field(alias=...) che rimanda alla chiave JSON esatta, più model_config = ConfigDict(populate_by_name=True) così puoi costruire il modello per nome del campo o per alias:

from pydantic import BaseModel, ConfigDict, Field


class Root(BaseModel):
    model_config = ConfigDict(populate_by_name=True)

    login: str
    public_repos: int = Field(alias="publicRepos")
    created_at: str = Field(alias="createdAt")

È questo che consente a Root.model_validate(api_json) di gestire payload camelCase reali in andata e ritorno mentre il tuo codice si legge in modo naturale.

TypedDict. Le chiavi che sono semplici identificatori vengono usate direttamente. Non appena compare una chiave non-identificatore, il convertitore passa alla sintassi funzionale TypedDict('User', {...}) per preservare la chiave esatta, argomento della prossima sezione.

Parole chiave Python e chiavi non-identificatore

Le chiavi JSON sono semplici stringhe, quindi nulla impedisce a un’API di inviare class, from o first-name. Ognuna sarebbe un errore di sintassi come nudo attributo Python, quindi il convertitore le sanifica.

Una chiave che è una parola chiave Python riceve un underscore finale: class diventa class_, from diventa from_. In modalità Pydantic mantiene anche un Field(alias=...) così il modello legge comunque la chiave originale trasmessa:

from pydantic import BaseModel, ConfigDict, Field


class Root(BaseModel):
    model_config = ConfigDict(populate_by_name=True)

    class_: str = Field(alias="class")
    from_: str = Field(alias="from")

Le chiavi con trattini, spazi o una cifra iniziale vengono sanificate in identificatori validi nelle modalità dataclass e Pydantic. TypedDict è l’unica modalità in grado di mantenere la chiave letterale, usando la forma funzionale così "first-name" sopravvive intatta:

from typing import TypedDict

Root = TypedDict("Root", {"first-name": str, "2fa": bool})

Il risultato funziona sempre, e in modalità TypedDict la chiave resta byte per byte identica a ciò che l’API ha inviato.

Fare il parsing del JSON con la classe generata

Generare la classe è metà del lavoro. Caricarci dentro il JSON è il punto in cui le tre modalità divergono nettamente, e in cui un’assunzione diffusa si rivela sbagliata.

dataclass. Per un oggetto piatto, json.loads più Root(**data) funziona direttamente:

import json
from dataclasses import dataclass
from typing import List


@dataclass
class Root:
    id: int
    name: str
    roles: List[str]


data = json.loads('{"id": 101, "name": "Ada Lovelace", "roles": ["admin"]}')
root = Root(**data)
print(root.name, root.roles)

Ma un dataclass non è ricorsivo. Se il JSON ha oggetti annidati, Root(**data) riempie il livello superiore e lascia ogni figlio come semplice dict, non la classe Owner che hai generato. Per fare il parsing di un intero albero, costruisci tu stesso i figli, usa una libreria come dacite o pydantic.dataclasses, oppure passa lo strumento in modalità Pydantic. Questa è l’insidia che la maggior parte dei convertitori non menziona mai.

Pydantic v2. Una sola chiamata fa il parsing e valida l’intero albero:

import json
from pydantic import BaseModel


class Root(BaseModel):
    id: int
    name: str


root = Root.model_validate(json.loads('{"id": 101, "name": "Ada Lovelace"}'))
print(root.name)

Una discordanza di tipo solleva un chiaro ValidationError invece di passare in silenzio. È questa la ricompensa per la dipendenza: il modello è un validatore a runtime, quindi una chiamata a model_validate che ritorna è una garanzia che i dati corrispondevano, non solo la convinzione di un type checker che lo facessero.

TypedDict. A runtime un TypedDict è un normale dict. Annotare data: Root = json.loads(text) serve puramente al type checker statico; nulla viene validato quando il codice gira. Se ti serve una vera applicazione delle regole, esegui mypy in CI oppure passa a Pydantic. Scegliere una modalità significa scegliere quanta garanzia a runtime vuoi, e quando un contratto deve andare oltre i tipi, la guida alla validazione con JSON Schema spiega come far rispettare la struttura da un capo all’altro.

Pydantic v2 vs v1 — cosa è cambiato

Il convertitore produce sintassi v2. Parecchie codebase usano ancora la v1, e incollare l’output v2 in un progetto v1 fallisce sui metodi rinominati più che sulla logica. Ecco la corrispondenza:

OperazionePydantic v2 (output dello strumento)Pydantic v1
Parsing di un dictmodel_validate(data)parse_obj(data)
Parsing di JSON grezzomodel_validate_json(text)parse_raw(text)
Configurare il modellomodel_config = ConfigDict(...)class Config interna
Serializzare in dictmodel_dump()dict()
Serializzare in JSONmodel_dump_json()json()

Anche il comportamento degli alias si è irrigidito: in v2 ti serve populate_by_name=True insieme a Field(alias=...) per costruire un modello sia per nome del campo sia per alias, ed è per questo che lo strumento lo include. Passa alla v2 se puoi, perché è più veloce ed è il bersaglio dello sviluppo attuale; altrimenti riscrivi model_validate in parse_obj e ConfigDict in una Config interna.

json-to-python vs quicktype vs datamodel-code-generator vs manuale

Non esiste un unico modo migliore per generare una classe Python da JSON. Dipende da dove vive il JSON e da cosa parti.

ApproccioIdeale perNota
Convertitore online (questo strumento, jsonlint, codeshack)Conversioni una tantum, payload sensibili, zero installazioniDeduce da un campione, interamente lato client
quicktypeOutput multi-linguaggio, codegen in pipelineAnch’esso guidato da un campione; il supporto Python è più povero su alias e scelta della modalità
datamodel-code-generatorGenerare Pydantic da un Schema JSON o OpenAPIL’input è uno schema, non un campione — più autorevole quando ne hai uno
Scrivere le classi a manoPayload minuscoli, imparare la sintassiControllo totale, ma noioso e facile alla deriva

La distinzione: un convertitore online e quicktype deducono entrambi i tipi da un campione di JSON, mentre datamodel-code-generator legge uno JSON Schema o una specifica OpenAPI come sua fonte di verità. Usa gli strumenti basati su campione per l’esplorazione e i casi una tantum; ricorri a quello guidato dallo schema quando un contratto esiste già. Se la tua codebase è in TypeScript invece che in Python, lo stesso approccio basato su campione si applica con il convertitore da JSON a TypeScript, e la guida alle interfacce da JSON a TypeScript approfondisce quel versante. Per l’aspetto della validazione a runtime in un linguaggio compilato e fortemente tipizzato, la guida alle struct da JSON a Rust offre un contrasto utile: serde è il Pydantic di Rust.

Insidie comuni nel generare Python da JSON

Le classi generate sono un punto di partenza. Fai attenzione a queste cose prima di affidarti all’output con dati reali.

  • Un solo campione rivela di rado ogni forma. Optional può essere dedotto solo da elementi dell’array che differiscono davvero. Incolla un array rappresentativo così l’opzionalità è accurata, non un’ipotesi tratta da un oggetto fortunato.
  • Un dataclass non valida. Root(**data) si limita ad assegnare i campi; non controlla alcun tipo e non ricorre in nulla. Se ti serve l’applicazione delle regole, usa Pydantic.
  • Il JSON annidato rompe Root(**data). Viene popolato solo il livello superiore; i figli restano dict. Passa a model_validate di Pydantic, oppure usa dacite.
  • Un campo sempre null diventa Optional[Any]. Trattalo come un segnaposto, non come un normale opzionale, e dagli un tipo reale non appena ne conosci uno.
  • Output v2 in un progetto v1. model_validate non sarà definito. Passa alla v2 o riscrivilo come parse_obj.
  • Una data lasciata come str non farà calcoli tra date. Cambia il campo in datetime, oppure in Pydantic usa un campo datetime così effettua il parsing dell’ISO 8601 per te.

Domande frequenti

Dovrei usare un dataclass, Pydantic o TypedDict per il JSON?

Usa un dataclass per un contenitore di dati interno a zero dipendenze. Usa Pydantic v2 quando fai il parsing o validi input non affidabili, perché applica i tipi a runtime. Usa TypedDict per aggiungere suggerimenti statici a un dict che hai già, senza costo a runtime. Quando i dati provengono da fuori del tuo controllo, scegli Pydantic come opzione predefinita.

Pydantic valida il JSON a runtime?

Sì. Root.model_validate(data) valida e converte i tipi mentre il codice gira, sollevando un ValidationError in caso di input errato. Un dataclass non fa né l’una né l’altra cosa — Root(**data) si limita ad assegnare i campi. Nemmeno un TypedDict lo fa; è un suggerimento per i type checker statici come mypy e si comporta come un semplice dict a runtime.

Come tipizzo un campo che il JSON a volte omette?

Tipizzalo come Optional[T]. Quando una chiave compare solo in alcuni elementi dell’array, il convertitore la marca automaticamente come Optional. In Pydantic, assegna al campo un valore predefinito come = None così una chiave mancante non fa scattare un errore di validazione. Un campo dataclass può avere un valore predefinito allo stesso modo con field(default=None).

Perché il mio dataclass non è riuscito a fare il parsing del JSON annidato?

Perché Root(**data) non è ricorsivo. Riempie i campi di primo livello e lascia gli oggetti annidati come semplici dict invece delle classi figlie che hai generato. Per fare il parsing dell’intero albero in una sola chiamata, passa a model_validate di Pydantic, oppure aggiungi la ricorsione con dacite o pydantic.dataclasses.

In quale tipo Python si trasforma un intero JSON grande?

int. Gli interi di Python hanno precisione arbitraria, quindi uno snowflake o un ID Discord oltre 2^53 resta un semplice int senza perdite. Non incontri mai il calo di precisione di JavaScript, e non devi mai scegliere tra i64 e u64 come ti costringe a fare Rust.

Come vengono gestite le chiavi JSON in camelCase in ciascuna modalità?

Un dataclass mantiene la chiave originale così Root(**data) continua a funzionare. Pydantic rinomina i campi in snake_case con Field(alias="camelKey") più populate_by_name=True, così gestisce in andata e ritorno dati reali di API. TypedDict usa la sintassi funzionale TypedDict('Name', {...}) per preservare qualsiasi chiave che non sia un identificatore valido.

Come gestisco una chiave JSON che è una parola chiave Python come class?

Il convertitore aggiunge un underscore finale, trasformando class in class_ così il codice è valido. In modalità Pydantic aggiunge anche Field(alias="class") che rimappa il campo alla chiave originale trasmessa, così il nome è legale e il modello legge comunque il payload reale.

Il mio JSON è privato quando uso un convertitore online da JSON a Python?

Sì. La conversione gira al 100% nel tuo browser con JavaScript. Il tuo JSON — inclusi token, ID e dati dei clienti — non lascia mai la pagina e non viene mai inviato a un server. Funziona persino offline una volta che la pagina è stata caricata. Quando sei pronto, prova il convertitore da JSON a Python sul tuo payload.

Tag: python json pydantic type-safety developer-tools

Articoli correlati

Vedi tutti gli articoli