JSON do Python
Generuj dataclassy Python z JSON
Wejście JSON
Wyjście Python
Czym jest konwersja JSON na dataclassy Python?
Konwersja JSON na dataclassy Python pobiera surowy obiekt JSON i generuje zestaw definicji dataclass z dokładnymi adnotacjami typów. Moduł dataclasses, wprowadzony w PEP 557 (Python 3.7), automatycznie generuje metody __init__, __repr__ i __eq__ na podstawie adnotowanych pól klasy. Przy pracy z API JSON, plikami konfiguracyjnymi lub kolejkami komunikatów dataclassy nadają danym typowaną strukturę, którą edytory i narzędzia do sprawdzania typów, takie jak mypy, mogą weryfikować na etapie programowania.
Funkcja json.loads() zwraca zwykłe słowniki i listy. Działają one poprawnie, ale nie mają informacji o typach: błędnie napisany klucz zwraca None zamiast zgłaszać błąd, a edytor nie może podpowiadać nazw pól. Dataclassy rozwiązują ten problem, mapując każdy klucz JSON na nazwane, typowane pole. Zagnieżdżone obiekty JSON stają się osobnymi definicjami dataclass, tablice stają się adnotacjami List[T], a wartości null stają się Optional[T] z wartością domyślną None.
Ręczne pisanie tych definicji to mechaniczna praca. Trzeba odczytać JSON, ustalić typ każdego pola na podstawie jego wartości, przekonwertować klucze z camelCase lub snake_case na konwencje Pythona i obsłużyć przypadki brzegowe, takie jak pola nullable i tablice z mieszanymi typami. Konwerter robi to wszystko w milisekundy. Wklejasz JSON, otrzymujesz poprawny kod dataclass i możesz działać dalej.
Dlaczego warto używać konwertera JSON do Python?
Ręczne tłumaczenie struktur JSON na definicje klas Python oznacza zgadywanie typów na podstawie przykładowych danych, układanie pól tak, żeby wymagane były przed opcjonalnymi, i aktualizowanie wszystkiego przy każdej zmianie API. Konwerter usuwa to tarcie.
Przypadki użycia JSON do Python
Tabela mapowania typów JSON na Python
Każda wartość JSON mapuje się na określoną adnotację typu Python. Poniższa tabela pokazuje, jak konwerter tłumaczy każdy typ JSON, uwzględniając zarówno składnię modułu typing (Python 3.7+), jak i wbudowaną składnię dostępną od Python 3.10.
| Typ JSON | Przykład | 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] |
Dokumentacja dekoratora dataclass
Dekorator @dataclass przyjmuje kilka parametrów, które zmieniają zachowanie generowanej klasy. Ten przewodnik opisuje opcje najbardziej przydatne przy pracy z danymi pochodzącymi z JSON.
| Dekorator / pole | Zachowanie | Kiedy używać |
|---|---|---|
| @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 oferuje trzy popularne sposoby definiowania typowanych struktur z JSON. Każdy pasuje do innego przypadku użycia. Dataclassy to opcja ze standardowej biblioteki bez zewnętrznych zależności. Pydantic dodaje walidację w czasie wykonania. TypedDict adnotuje zwykłe słowniki bez tworzenia nowej klasy.
Przykłady kodu
Poniższe przykłady pokazują, jak używać wygenerowanych dataclass w Python, jak generować je programistycznie z JavaScript oraz jak korzystać z alternatywnych podejść, takich jak Pydantic i narzędzia 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]