Конвертер JSON в классы Python
Генерируйте типизированные классы Python из JSON с методами from_dict и to_dict для разбора и сериализации.
Генерация типизированных классов Python из JSON
json.loads возвращает вложенные словари, поэтому опечатки в ключах обнаруживаются только во время выполнения, а редактор ничего не может автодополнить. Конвертер создаёт класс для каждого объекта в вашем JSON с аннотированными атрибутами (str, int, float, bool, List[...]), статическим методом from_dict, который проверяет тип каждого значения при разборе, и методом to_dict, превращающим объект обратно в словарь для JSON. Используется только модуль typing из стандартной библиотеки.
Как пользоваться
- Вставьте пример JSON — например, полезную нагрузку вебхука или ответ API.
- Задайте имя корневого класса, например Order.
- Сохраните код как модуль и разбирайте данные через Order.from_dict(json.loads(text)); перед отправкой вызовите to_dict() и передайте результат в json.dumps.
Часто задаваемые вопросы
- Это dataclass или модели Pydantic?
- Ни то ни другое. Это обычные классы с аннотациями типов и явными методами from_dict/to_dict, поэтому сторонние пакеты не нужны. Если ваш проект уже использует Pydantic, можно добавить @dataclass или перенести поля в модель Pydantic.
- Что произойдёт, если данные не соответствуют типам?
- Сгенерированные вспомогательные функции используют проверки assert isinstance, поэтому from_dict выбрасывает AssertionError, если значение имеет неожиданный тип. Учтите, что при запуске Python с флагом -O проверки assert пропускаются.
- Какая версия Python нужна?
- Код использует аннотации из модуля typing и работает на Python 3.7 и новее.
Пример: JSON в Python
Исходный JSON
{
"order_id": "A-1001",
"total": 59.9,
"paid": true,
"items": [{ "sku": "BOOK-1", "quantity": 2 }]
}Сгенерированный код: Python (Order)
from typing import Any, List, TypeVar, Callable, Type, cast
T = TypeVar("T")
def from_str(x: Any) -> str:
assert isinstance(x, str)
return x
def from_int(x: Any) -> int:
assert isinstance(x, int) and not isinstance(x, bool)
return x
def from_float(x: Any) -> float:
assert isinstance(x, (float, int)) and not isinstance(x, bool)
return float(x)
def from_bool(x: Any) -> bool:
assert isinstance(x, bool)
return x
def from_list(f: Callable[[Any], T], x: Any) -> List[T]:
assert isinstance(x, list)
return [f(y) for y in x]
def to_float(x: Any) -> float:
assert isinstance(x, (int, float))
return x
def to_class(c: Type[T], x: Any) -> dict:
assert isinstance(x, c)
return cast(Any, x).to_dict()
class Item:
sku: str
quantity: int
def __init__(self, sku: str, quantity: int) -> None:
self.sku = sku
self.quantity = quantity
@staticmethod
def from_dict(obj: Any) -> 'Item':
assert isinstance(obj, dict)
sku = from_str(obj.get("sku"))
quantity = from_int(obj.get("quantity"))
return Item(sku, quantity)
def to_dict(self) -> dict:
result: dict = {}
result["sku"] = from_str(self.sku)
result["quantity"] = from_int(self.quantity)
return result
class Order:
order_id: str
total: float
paid: bool
items: List[Item]
def __init__(self, order_id: str, total: float, paid: bool, items: List[Item]) -> None:
self.order_id = order_id
self.total = total
self.paid = paid
self.items = items
@staticmethod
def from_dict(obj: Any) -> 'Order':
assert isinstance(obj, dict)
order_id = from_str(obj.get("order_id"))
total = from_float(obj.get("total"))
paid = from_bool(obj.get("paid"))
items = from_list(Item.from_dict, obj.get("items"))
return Order(order_id, total, paid, items)
def to_dict(self) -> dict:
result: dict = {}
result["order_id"] = from_str(self.order_id)
result["total"] = to_float(self.total)
result["paid"] = from_bool(self.paid)
result["items"] = from_list(lambda x: to_class(Item, x), self.items)
return result
def order_from_dict(s: Any) -> Order:
return Order.from_dict(s)
def order_to_dict(x: Order) -> Any:
return to_class(Order, x)