JSON to Python
Generování Python dataclass definic z JSON
Vstup JSON
Výstup Python
Co je převod JSON na Python dataclass?
Převod JSON na Python dataclass vezme surový JSON objekt a vyprodukuje sadu definic Python dataclass s přesnými typovými anotacemi. Modul dataclasses, představený v PEP 557 (Python 3.7), generuje metody __init__, __repr__ a __eq__ z anotovaných polí třídy. Při práci s JSON API, konfiguračními soubory nebo frontami zpráv vám dataclasses dávají datům typovanou strukturu, kterou mohou editory a typové kontroly jako mypy ověřovat při vývoji.
Funkce json.loads() vrací prosté slovníky a seznamy. Ty fungují, ale nemají žádné informace o typech: překlep v klíči vrátí None místo vyvolání výjimky a editor nemůže doplňovat názvy polí. Dataclasses tento problém řeší mapováním každého klíče JSON na pojmenované, typované pole. Vnořené JSON objekty se stávají samostatnými definicemi dataclass, pole se stávají anotacemi List[T] a hodnoty null se stávají Optional[T] s výchozí hodnotou None.
Ruční psaní těchto definic je mechanická práce. Musíte si přečíst JSON, zjistit typ každého pole z jeho hodnoty, převést klíče z camelCase nebo snake_case do konvencí Pythonu a ošetřit hraniční případy jako nulovatelná pole a pole se smíšenými typy. Převodník toto vše zvládne v milisekundách. Vložíte JSON, získáte správný kód dataclass a pokračujete dále.
Proč používat převodník JSON na Python?
Ruční překlad JSON struktur do Python definic tříd znamená odhadovat typy ze vzorových dat, přeuspořádávat pole tak, aby povinná přicházela před volitelnými, a aktualizovat vše při změně API. Převodník toto tření odstraňuje.
Případy použití JSON na Python
Mapování typů JSON na Python
Každá hodnota JSON se mapuje na konkrétní typovou anotaci Pythonu. Tabulka níže ukazuje, jak převodník překládá každý typ JSON, a to jak syntaxí modulu typing (Python 3.7+), tak vestavěnou syntaxí dostupnou od Pythonu 3.10 výše.
| Typ JSON | Příklad | 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] |
Přehled dekorátoru dataclass
Dekorátor @dataclass přijímá několik parametrů, které mění chování generované třídy. Tento přehled pokrývá možnosti nejrelevantnější při práci s daty odvozenými z JSON.
| Dekorátor / Pole | Chování | Použít, když |
|---|---|---|
| @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 má tři běžné způsoby definování typovaných struktur z JSON. Každý se hodí pro jiný případ použití. Dataclasses jsou variantou standardní knihovny bez závislostí. Pydantic přidává validaci za běhu. TypedDict anotuje prosté slovníky bez vytváření nové třídy.
Příklady kódu
Tyto příklady ukazují, jak používat vygenerované dataclasses v Pythonu, jak je programově vytvářet z JavaScriptu a jak používat alternativní přístupy jako Pydantic a CLI nástroje.
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]