← Назад к вопросам

Как десериализовать JSON в объект?

1.2 Junior🔥 141 комментариев
#Python Core#REST API и HTTP

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как десериализовать JSON в объект?

Десериализация JSON (парсинг JSON в Python объекты) — это одна из самых частых операций при работе с API и данными. В Python это очень просто, но есть разные подходы в зависимости от сложности.

Базовый подход: json.loads()

json.loads() — преобразует JSON строку в Python объект:

import json

# JSON строка
json_string = '{"name": "Alice", "age": 30, "city": "Moscow"}'

# Десериализация
data = json.loads(json_string)

print(data)          # {'name': 'Alice', 'age': 30, 'city': 'Moscow'}
print(type(data))    # <class 'dict'>
print(data['name'])  # Alice

JSON типы → Python типы:

JSONPython
object {}dict
array []list
string "text"str
number 123int
number 1.23float
trueTrue
falseFalse
nullNone
json_string = '''
{
  "name": "Bob",
  "age": 25,
  "active": true,
  "balance": 100.50,
  "tags": ["python", "developer"],
  "address": null
}
'''

data = json.loads(json_string)

print(data['name'])      # Bob (str)
print(data['age'])       # 25 (int)
print(data['active'])    # True (bool)
print(data['balance'])   # 100.5 (float)
print(data['tags'])      # ['python', 'developer'] (list)
print(data['address'])   # None (NoneType)

Чтение JSON из файла: json.load()

Если JSON находится в файле, используйте json.load() (без 's'):

import json

# Из файла
with open('data.json', 'r', encoding='utf-8') as f:
    data = json.load(f)  # Заметьте: load(), не loads()

print(data)
print(data['users'][0]['name'])

Файл data.json:

{
  "users": [
    {"id": 1, "name": "Alice"},
    {"id": 2, "name": "Bob"}
  ]
}

Десериализация в объекты (Classes)

Часто нужно преобразовать JSON не в dict, а в полноценный Python объект (класс).

Способ 1: Вручную преобразовать dict в объект

import json
from dataclasses import dataclass

@dataclass
class User:
    name: str
    age: int
    city: str

json_string = '{"name": "Alice", "age": 30, "city": "Moscow"}'

data = json.loads(json_string)
# Преобразовать dict в User объект
user = User(**data)  # Распаковка параметров

print(user)              # User(name='Alice', age=30, city='Moscow')
print(user.name)         # Alice
print(type(user))        # <class '__main__.User'>

Способ 2: Пользовательская функция (object_hook)

import json

class User:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def __repr__(self):
        return f"User(name='{self.name}', age={self.age})"

def user_decoder(dct):
    if 'name' in dct and 'age' in dct:
        return User(dct['name'], dct['age'])
    return dct

json_string = '{"name": "Alice", "age": 30}'

# object_hook вызывается для каждого dict
user = json.loads(json_string, object_hook=user_decoder)

print(user)        # User(name='Alice', age=30)
print(user.name)   # Alice

Способ 3: Модуль dataclasses.asdict()

from dataclasses import dataclass, asdict
import json

@dataclass
class User:
    name: str
    age: int

json_string = '{"name": "Alice", "age": 30}'
data = json.loads(json_string)

# Преобразовать dict в dataclass
user = User(**data)

print(asdict(user))  # {'name': 'Alice', 'age': 30}

Лучший способ: Pydantic (валидация + десериализация)

Pydantic — самая популярная библиотека для работы с JSON в Python:

pip install pydantic

Использование:

from pydantic import BaseModel
import json

class User(BaseModel):
    name: str
    age: int
    city: str = "Unknown"  # Значение по умолчанию

json_string = '{"name": "Alice", "age": 30}'

# Десериализовать и валидировать одновременно
user = User.model_validate_json(json_string)

print(user)              # name='Alice' age=30 city='Unknown'
print(user.name)         # Alice
print(user.age)          # 30
print(user.city)         # Unknown
print(user.model_dump()) # {'name': 'Alice', 'age': 30, 'city': 'Unknown'}

Валидация типов:

from pydantic import BaseModel, ValidationError

class User(BaseModel):
    name: str
    age: int  # Должен быть int

# ✅ Правильно
user = User.model_validate_json('{"name": "Alice", "age": 30}')

# ❌ Ошибка: age должен быть int
try:
    user = User.model_validate_json('{"name": "Alice", "age": "thirty"}')
except ValidationError as e:
    print(e)
    # age: Input should be a valid integer, unable to parse string as an integer

Сложные типы:

from pydantic import BaseModel
from typing import List
import json

class Address(BaseModel):
    street: str
    city: str

class User(BaseModel):
    name: str
    address: Address      # Вложенный объект
    hobbies: List[str]   # Список

json_string = '''
{
  "name": "Alice",
  "address": {"street": "Main St", "city": "Moscow"},
  "hobbies": ["reading", "coding"]
}
'''

user = User.model_validate_json(json_string)

print(user.name)                    # Alice
print(user.address.city)            # Moscow
print(user.hobbies)                 # ['reading', 'coding']
print(user.hobbies[0])              # reading

Обработка ошибок

Поймать ошибки парсинга:

import json
from json import JSONDecodeError

json_string = '{"name": "Alice", age: 30}'  # Неправильный JSON (нет кавычек у age)

try:
    data = json.loads(json_string)
except JSONDecodeError as e:
    print(f"Ошибка парсинга JSON: {e}")
    print(f"Позиция: {e.pos}")
    # Ошибка парсинга JSON: Expecting property name enclosed in double quotes

С Pydantic:

from pydantic import BaseModel, ValidationError

class User(BaseModel):
    name: str
    age: int

try:
    user = User.model_validate_json('{invalid json}')
except ValidationError as e:
    print(f"Ошибка валидации: {e}")

Десериализация со стандартом parse_obj()

from dataclasses import dataclass
import json
from typing import Type, TypeVar

T = TypeVar('T')

@dataclass
class Address:
    street: str
    city: str

@dataclass  
class User:
    name: str
    address: Address

def parse_json(json_string: str, model_class: Type[T]) -> T:
    data = json.loads(json_string)
    
    # Рекурсивно преобразовать вложенные объекты
    if model_class == User:
        data['address'] = Address(**data['address'])
    
    return model_class(**data)

json_string = '{"name": "Alice", "address": {"street": "Main", "city": "Moscow"}}'

user = parse_json(json_string, User)

print(user.name)              # Alice
print(user.address.city)      # Moscow

Сравнение подходов

МетодПростотаВалидацияСкоростьДля
json.loads()⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐Простые данные
object_hook⭐⭐⭐⭐⭐⭐⭐Custom классы
dataclass⭐⭐⭐⭐⚠️⭐⭐⭐⭐Type hints
Pydantic⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐Production

Практический пример: API запрос

import requests
from pydantic import BaseModel
from typing import List

class Repository(BaseModel):
    id: int
    name: str
    url: str
    stars: int = 0

class User(BaseModel):
    login: str
    repositories: List[Repository]

# Запрос к GitHub API
response = requests.get('https://api.github.com/users/torvalds/repos')

# Десериализация в список объектов
repos = [Repository(**repo) for repo in response.json()]

for repo in repos[:3]:
    print(f"{repo.name}: {repo.stars} ⭐")

Выводы

  • Простой JSON → dict: используй json.loads()
  • Файл → dict: используй json.load()
  • JSON → объект: используй object_hook или распаковку параметров
  • Production код: используй Pydantic для валидации и типизации
  • Сложные структуры: Pydantic поддерживает вложенные объекты и списки
  • Обработка ошибок: ловите JSONDecodeError или ValidationError
Как десериализовать JSON в объект? | PrepBro