Привет! Когда программа работает, данные хранятся в памяти в виде объектов Python. Но чтобы сохранить их на диск, отправить по сети или передать другой программе, нужно преобразовать объекты в формат, понятный другим системам. Это называется сериализацией.
В этой статье мы разберём:
- Что такое сериализация и десериализация
- Форматы: JSON, pickle
- Сериализация кастомных объектов
- Сохранение и загрузка данных
- Практические примеры
- Что нужно знать перед началом
- Основная часть
- Что такое сериализация и десериализация
- Формат JSON
- Формат pickle
- JSON vs pickle
- Сериализация кастомных объектов
- Сериализация в другие форматы
- XML
- YAML
- Пример из реальной жизни
- Задачи для закрепления
- Нюансы и подводные камни
- Pickle опасен
- JSON не поддерживает все типы
- Кодировка
- Циклические ссылки
- Частые ошибки и как их избежать
- Ошибка 1: Попытка сериализовать datetime в JSON
- Ошибка 2: Путаница между json.dumps() и json.dump()
- Ошибка 3: Загрузка pickle из ненадёжного источника
- Шпаргалка
- Заключение
- КВИЗ
- Что дальше?
Что нужно знать перед началом
Для этого урока тебе понадобится:
- Установленный Python
- Базовое понимание объектов и файлов
Совет: Сериализация — это процесс превращения объекта в байтовый поток или строку для хранения или передачи.
Основная часть
Что такое сериализация и десериализация
Сериализация — процесс преобразования объекта в формат, который можно сохранить или передать.
Десериализация — обратный процесс: восстановление объекта из сериализованного формата.
# Сериализация: объект → JSON-строка
data = {"name": "Анна", "age": 25}
json_string = json.dumps(data)
# Десериализация: JSON-строка → объект
data = json.loads(json_string)Совет: Сериализация нужна для хранения данных (файлы, БД) и передачи по сети (API, микросервисы).
Формат JSON
JSON — самый популярный формат для обмена данными. Он поддерживается почти всеми языками программирования.
import json
data = {
"name": "Анна",
"age": 25,
"is_active": True,
"scores": [95, 87, 92],
"address": None
}
# Сериализация в JSON-строку
json_string = json.dumps(data, ensure_ascii=False, indent=4)
print(json_string)
# Десериализация из JSON-строки
restored_data = json.loads(json_string)
print(restored_data)Результат:
{
"name": "Анна",
"age": 25,
"is_active": true,
"scores": [95, 87, 92],
"address": null
}Совет:
json.dumps()иjson.loads()— для строк.json.dump()иjson.load()— для файлов.
Формат pickle
Pickle — встроенный формат Python для сериализации объектов. Он поддерживает все типы Python, включая кастомные классы.
import pickle
data = {
"name": "Анна",
"age": 25,
"scores": [95, 87, 92]
}
# Сериализация в байты
pickled_data = pickle.dumps(data)
print(pickled_data) # b'\x80\x04\x95...'
# Десериализация из байтов
restored_data = pickle.loads(pickled_data)
print(restored_data)Работа с файлами:
# Сохранение в файл
with open("data.pkl", "wb") as file:
pickle.dump(data, file)
# Загрузка из файла
with open("data.pkl", "rb") as file:
loaded_data = pickle.load(file)
print(loaded_data)Важно: Pickle опасен при загрузке данных из ненадёжных источников — может выполнить вредоносный код.
JSON vs pickle
| Характеристика | JSON | pickle |
|---|---|---|
| Человекочитаемый | Да | Нет |
| Безопасность | Безопасен | Опасен |
| Поддержка других языков | Да | Нет (только Python) |
| Скорость | Медленнее | Быстрее |
| Поддерживает кастомные классы | Нет | Да |
| Размер данных | Больше | Меньше |
Совет: Для API используй JSON. Для внутреннего хранения в Python — можно использовать pickle.
Сериализация кастомных объектов
По умолчанию JSON не умеет сериализовать кастомные классы.
class User:
def __init__(self, name, age):
self.name = name
self.age = age
user = User("Анна", 25)
# Ошибка! TypeError: Object of type User is not JSON serializable
# json.dumps(user)Решение 1: Функция default
def user_to_dict(obj):
if isinstance(obj, User):
return {"name": obj.name, "age": obj.age}
raise TypeError(f"Объект {obj} не сериализуем")
json_string = json.dumps(user, default=user_to_dict)
print(json_string) # {"name": "Анна", "age": 25}Решение 2: Метод to_dict
class User:
def __init__(self, name, age):
self.name = name
self.age = age
def to_dict(self):
return {"name": self.name, "age": self.age}
user = User("Анна", 25)
json_string = json.dumps(user.to_dict())
print(json_string) # {"name": "Анна", "age": 25}Решение 3: Pickle (для Python-объектов)
user = User("Анна", 25)
pickled_user = pickle.dumps(user)
restored_user = pickle.loads(pickled_user)
print(restored_user.name, restored_user.age) # Анна 25Сериализация в другие форматы
XML
import xml.etree.ElementTree as ET
def dict_to_xml(data, root_name="root"):
root = ET.Element(root_name)
for key, value in data.items():
child = ET.SubElement(root, key)
child.text = str(value)
return ET.tostring(root, encoding="unicode")
data = {"name": "Анна", "age": "25"}
xml_string = dict_to_xml(data)
print(xml_string) # <root><name>Анна</name><age>25</age></root>YAML
# pip install pyyaml
import yaml
data = {"name": "Анна", "age": 25}
yaml_string = yaml.dump(data)
print(yaml_string)
restored = yaml.load(yaml_string, Loader=yaml.FullLoader)
print(restored)Пример из реальной жизни
Сохранение настроек приложения:
import json
from datetime import datetime
class AppConfig:
def __init__(self, theme="dark", language="ru"):
self.theme = theme
self.language = language
self.updated_at = datetime.now()
def to_dict(self):
return {
"theme": self.theme,
"language": self.language,
"updated_at": self.updated_at.isoformat()
}
@classmethod
def from_dict(cls, data):
config = cls(data["theme"], data["language"])
config.updated_at = datetime.fromisoformat(data["updated_at"])
return config
# Сохранение
config = AppConfig()
with open("config.json", "w", encoding="utf-8") as file:
json.dump(config.to_dict(), file, ensure_ascii=False, indent=4)
# Загрузка
with open("config.json", "r", encoding="utf-8") as file:
data = json.load(file)
loaded_config = AppConfig.from_dict(data)
print(loaded_config.theme, loaded_config.language)Задачи для закрепления
Задача 1. Сериализуй словарь {"name": "Иван", "age": 30} в JSON-строку.
Задача 2. Сериализуй объект пользователя в JSON с помощью метода to_dict().
Задача 3. Сохрани данные в файл с помощью pickle.
Задача 4. Загрузи данные из файла с помощью pickle.
Задача 5. В чём разница между JSON и pickle?
Ответы:
Задача 1.
import json
data = {"name": "Иван", "age": 30}
json_str = json.dumps(data, ensure_ascii=False)
print(json_str) # {"name": "Иван", "age": 30}Задача 2.
class User:
def __init__(self, name, age):
self.name = name
self.age = age
def to_dict(self):
return {"name": self.name, "age": self.age}
user = User("Иван", 30)
json_str = json.dumps(user.to_dict())
print(json_str) # {"name": "Иван", "age": 30}Задача 3.
import pickle
data = {"name": "Иван", "age": 30}
with open("data.pkl", "wb") as file:
pickle.dump(data, file)Задача 4.
with open("data.pkl", "rb") as file:
loaded = pickle.load(file)
print(loaded) # {'name': 'Иван', 'age': 30}Задача 5.
# JSON — безопасен, человекочитаемый, поддерживается другими языками.
# pickle — быстрее, поддерживает кастомные классы, но опасен и только для Python.Нюансы и подводные камни
Pickle опасен
Никогда не загружай pickle из ненадёжных источников. Он может выполнить вредоносный код.
JSON не поддерживает все типы
datetime, Decimal, set, кастомные классы — не сериализуются по умолчанию.
Кодировка
Для русского текста используй ensure_ascii=False в JSON.
Циклические ссылки
Pickle поддерживает циклические ссылки, JSON — нет.
Частые ошибки и как их избежать
Ошибка 1: Попытка сериализовать datetime в JSON
Преобразуй в строку через isoformat() или используй кастомный encoder.
Ошибка 2: Путаница между json.dumps() и json.dump()
dumps() — в строку. dump() — в файл.
Ошибка 3: Загрузка pickle из ненадёжного источника
Используй JSON для данных из внешних источников.
Шпаргалка
| Формат | Для строк | Для файлов |
|---|---|---|
| JSON | json.dumps(), json.loads() | json.dump(), json.load() |
| pickle | pickle.dumps(), pickle.loads() | pickle.dump(), pickle.load() |
Заключение
Сегодня мы:
- Узнали, что такое сериализация и десериализация
- Изучили форматы JSON и pickle
- Научились сериализовать кастомные объекты
- Практические примеры








