JSON to Python
Python-Dataclasses aus JSON generieren
JSON-Eingabe
Python-Ausgabe
Was ist die JSON-zu-Python-Dataclass-Konvertierung?
Die JSON-zu-Python-Dataclass-Konvertierung nimmt ein rohes JSON-Objekt und erzeugt daraus eine Menge von Python-Dataclass-Definitionen mit korrekten Typ-Annotationen. Das dataclasses-Modul, eingeführt mit PEP 557 (Python 3.7), generiert automatisch __init__, __repr__ und __eq__-Methoden aus annotierten Klassenfeldern. Beim Arbeiten mit JSON-APIs, Konfigurationsdateien oder Message Queues verleihen Dataclasses den Daten eine typisierte Struktur, die Editoren und Type-Checker wie mypy zur Entwicklungszeit überprüfen können.
Pythons json.loads() gibt einfache Dicts und Listen zurück. Diese funktionieren, tragen aber keine Typinformationen: Ein falsch geschriebener Schlüssel liefert None, anstatt einen Fehler auszulösen, und der Editor kann Feldnamen nicht autovervollständigen. Dataclasses lösen dieses Problem, indem jeder JSON-Schlüssel einem benannten, typisierten Feld zugeordnet wird. Verschachtelte JSON-Objekte werden zu separaten Dataclass-Definitionen, Arrays werden zu List[T]-Annotationen, und null-Werte werden zu Optional[T] mit einem Standardwert von None.
Diese Definitionen von Hand zu schreiben ist mechanische Arbeit. Man liest das JSON, leitet den Typ jedes Feldes aus seinem Wert ab, konvertiert Schlüssel von camelCase oder snake_case in Python-Konventionen und behandelt Sonderfälle wie Nullable-Felder und Arrays mit gemischten Typen. Ein Konverter erledigt das alles in Millisekunden. JSON einfügen, korrekten Dataclass-Code erhalten und weitermachen.
Warum einen JSON-zu-Python-Konverter verwenden?
JSON-Strukturen von Hand in Python-Klassendefinitionen zu übersetzen bedeutet, Typen aus Beispieldaten zu raten, Felder so anzuordnen, dass Pflichtfelder vor optionalen kommen, und alles zu aktualisieren, wenn sich die API ändert. Ein Konverter beseitigt diese Reibung.
JSON-zu-Python-Anwendungsfälle
JSON-zu-Python-Typ-Mapping
Jeder JSON-Wert wird einer bestimmten Python-Typ-Annotation zugeordnet. Die Tabelle zeigt, wie der Konverter jeden JSON-Typ übersetzt — sowohl die typing-Modul-Syntax (Python 3.7+) als auch die eingebaute Syntax ab Python 3.10.
| JSON-Typ | Beispiel | 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] |
Dataclass-Decorator-Referenz
Der @dataclass-Decorator akzeptiert mehrere Parameter, die das Verhalten der generierten Klasse beeinflussen. Diese Referenz behandelt die Optionen, die beim Arbeiten mit JSON-abgeleiteten Daten am relevantesten sind.
| Decorator / Feld | Verhalten | Einsatz wenn |
|---|---|---|
| @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 bietet drei gängige Wege, typisierte Strukturen aus JSON zu definieren. Jeder eignet sich für einen anderen Anwendungsfall. Dataclasses sind die Standardbibliothek-Option ohne externe Abhängigkeiten. Pydantic fügt Laufzeit-Validierung hinzu. TypedDict annotiert gewöhnliche Dicts, ohne eine neue Klasse zu erstellen.
Code-Beispiele
Diese Beispiele zeigen, wie generierte Dataclasses in Python verwendet werden, wie sie programmatisch aus JavaScript erzeugt werden und wie alternative Ansätze wie Pydantic und CLI-Tools eingesetzt werden.
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]