Как десериализовать JSON в объект?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Как десериализовать 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 типы:
| JSON | Python |
|---|---|
object {} | dict |
array [] | list |
string "text" | str |
number 123 | int |
number 1.23 | float |
| true | True |
| false | False |
| null | None |
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