Найти в Дзене
Анастасия Софт

🧠 Сериализация и десериализация в Python: просто, мощно, с пояснениями

Иногда нашим программам нужно сохранить "всё как есть": объекты, данные, состояние — в файл или переслать по сети. Для этого Python предлагает удобные инструменты: сериализация (преобразование объекта в байты) и десериализация (обратное превращение в объект). Самые популярные модули: import pickle
# Класс, объект которого мы хотим сериализовать
class User:
def __init__(self, name, age):
self.name = name # Имя пользователя
self.age = age # Возраст пользователя
# Создаём экземпляр класса
user = User("Alice", 30)
# Сохраняем объект в файл
with open("user.pkl", "wb") as f: # 'wb' означает запись в бинарном режиме
pickle.dump(user, f) # Сериализация объекта user # Загружаем объект обратно из файла
with open("user.pkl", "rb") as f: # 'rb' — чтение в бинарном режиме
loaded_user = pickle.load(f) # Десериализация объекта
print(loaded_user.name) # Вывод: Alice 💡 Важно: pickle не безопасен. Никогда не загружай фай
Оглавление

Иногда нашим программам нужно сохранить "всё как есть": объекты, данные, состояние — в файл или переслать по сети. Для этого Python предлагает удобные инструменты: сериализация (преобразование объекта в байты) и десериализация (обратное превращение в объект).

Самые популярные модули:

  • pickle — сериализует почти всё (но не безопасен для данных из ненадёжных источников).
  • json — сериализует данные в человекочитаемом виде (строго типизирован).
  • marshal — используется интерпретатором Python (но не рекомендуется для обычного кода).
  • dill — расширение pickle, умеет больше.

🔰 Для новичков: сериализуем объект с помощью pickle

import pickle

# Класс, объект которого мы хотим сериализовать
class User:
def __init__(self, name, age):
self.name = name # Имя пользователя
self.age = age # Возраст пользователя

# Создаём экземпляр класса
user = User("Alice", 30)

# Сохраняем объект в файл
with open("user.pkl", "wb") as f: # 'wb' означает запись в бинарном режиме
pickle.dump(user, f) # Сериализация объекта user

# Загружаем объект обратно из файла
with open("user.pkl", "rb") as f: # 'rb' — чтение в бинарном режиме
loaded_user = pickle.load(f) # Десериализация объекта

print(loaded_user.name) # Вывод: Alice

💡 Важно: pickle не безопасен. Никогда не загружай файлы от незнакомцев — это как кушать суши с асфальта.

🔁 Задача с собеседования: сериализуем словарь с кастомным классом

import pickle

class Product:
def __init__(self, id, title, price):
self.id = id
self.title = title
self.price = price

def __repr__(self):
return f"{self.title} (${self.price})"

# Словарь, где ключи — строки, значения — объекты Product
products = {
"item1": Product(1, "Book", 12.99),
"item2": Product(2, "Pen", 1.50)
}

# Сохраняем словарь
with open("products.pkl", "wb") as f:
pickle.dump(products, f)

# Восстанавливаем
with open("products.pkl", "rb") as f:
loaded_products = pickle.load(f)

print(loaded_products["item1"]) # Вывод: Book ($12.99)

🔎 Комментарий: pickle справляется даже со сложными структурами данных. Главное — все объекты внутри должны быть сериализуемыми.

🔥 Продвинутый уровень: сериализуем с __getstate__ и __setstate__

Иногда мы хотим сериализовать не все поля объекта, например, пропустить кэш или временные переменные. Используем __getstate__ и __setstate__:

class Session:
def __init__(self, user, token):
self.user = user
self.token = token
self.cache = {"last_action": "login"} # временное поле

def __getstate__(self):
state = self.__dict__.copy()
del state["cache"] # не сериализуем кэш
return state

def __setstate__(self, state):
self.__dict__.update(state)
self.cache = {} # создаём пустой кэш при десериализации

# Проверим сериализацию
session = Session("admin", "XYZ123")
with open("session.pkl", "wb") as f:
pickle.dump(session, f)

with open("session.pkl", "rb") as f:
restored = pickle.load(f)

print(restored.cache) # Вывод: {}

🤓 Уровень "гуру": сериализация через JSON с __dict__ и кастомным классом

Если вы хотите сериализовать объекты в формат JSON (например, для REST API), нужно немного вручную.

import json

class Note:
def __init__(self, title, tags):
self.title = title
self.tags = tags

note = Note("Learn Python", ["coding", "fun"])

# Преобразуем объект в словарь
note_dict = note.__dict__

# Сериализуем в JSON
json_string = json.dumps(note_dict)
print(json_string) # {"title": "Learn Python", "tags": ["coding", "fun"]}

# Десериализуем обратно
note_data = json.loads(json_string)
restored_note = Note(**note_data)
print(restored_note.title) # Learn Python

💼 Частый вопрос на собеседовании:

❓ Как сериализовать объект, в котором есть несериализуемое поле (например, threading.Lock)?

Ответ:
Исключить это поле из сериализации через __getstate__, а потом создать заново в __setstate__.

🧩 Ещё одна задача: сериализуем иерархию объектов

Класс Person, поле address, объект класса Address.

class Address:
def __init__(self, city):
self.city = city

class Person:
def __init__(self, name, address):
self.name = name
self.address = address

person = Person("Bob", Address("London"))

# Сохраняем
with open("person.pkl", "wb") as f:
pickle.dump(person, f)

# Загружаем
with open("person.pkl", "rb") as f:
loaded = pickle.load(f)

print(loaded.address.city) # London

🐍 Юмор в тему

Сериализация — это когда твой объект, как Феникс, умирает в файл, чтобы потом возродиться обратно в память… только без лишнего веса вроде кэша.

🧊 Десериализация в Python — достаём объекты из файла (или сети!)

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

🎯 1. Простейший пример с pickle

import pickle

# Допустим, у нас уже есть файл с сериализованным объектом (например, User)
class User:
def __init__(self, name, age):
self.name = name
self.age = age

# Десериализация из файла
with open("user.pkl", "rb") as f:
user = pickle.load(f) # загружаем объект

print(user.name) # Alice
print(user.age) # 30

🔍 Что здесь происходит:

  • Открываем файл в бинарном режиме на чтение ('rb').
  • pickle.load() сам "распознаёт", как воссоздать объект.
  • Объект возвращается полностью: методы, поля, даже вложенные объекты.

🧩 2. Десериализация сложных структур (словарь с объектами)

# Допустим, в файле сохранён словарь с объектами Product
class Product:
def __init__(self, id, title, price):
self.id = id
self.title = title
self.price = price

def __repr__(self):
return f"{self.title} (${self.price})"

# Десериализуем словарь
with open("products.pkl", "rb") as f:
products = pickle.load(f)

print(products["item1"]) # Book ($12.99)

Важно: Все классы должны быть определены ДО загрузки, иначе pickle не сможет воссоздать объект.

🦾 3. Десериализация с кастомной логикой (__setstate__)

class Session:
def __init__(self, user, token):
self.user = user
self.token = token
self.cache = {"last_action": "login"}

def __getstate__(self):
state = self.__dict__.copy()
del state["cache"] # не сериализуем кэш
return state

def __setstate__(self, state):
self.__dict__.update(state)
self.cache = {} # после загрузки создаём пустой кэш

# Восстановление объекта из файла
with open("session.pkl", "rb") as f:
session = pickle.load(f)

print(session.user) # admin
print(session.cache) # {}

🔧 Преимущество:

Мы контролируем, что именно сохраняется и что происходит при загрузке. Особенно полезно для временных или невалидируемых полей.

🧙‍♂️ 4. JSON-десериализация

Когда работаешь с REST API, ты получаешь JSON. А это не pickle, так что нужно собирать объекты вручную.

import json

class Note:
def __init__(self, title, tags):
self.title = title
self.tags = tags

# JSON-строка, полученная из API или файла
json_string = '{"title": "Learn Python", "tags": ["fun", "code"]}'

# Преобразуем JSON в словарь
data = json.loads(json_string)

# Превращаем в объект Note
note = Note(**data)

print(note.title) # Learn Python

🧪 5. Задача с собеседования: безопасная десериализация

❓ Как безопасно десериализовать JSON, в котором может быть неизвестная структура?

import json

def safe_deserialize(json_string):
try:
return json.loads(json_string)
except json.JSONDecodeError:
return None # или логировать ошибку

data = safe_deserialize('{"key": "value"}')
print(data["key"]) # value

🤔 Совет:

  • JSON — безопаснее pickle, но требует ручного создания объектов.
  • pickle — удобнее, но только для "своих" данных.

💼 Интервью-вопрос: Десериализация с восстановлением связи объектов

class Author:
def __init__(self, name):
self.name = name

class Book:
def __init__(self, title, author: Author):
self.title = title
self.author = author

# Загрузка из файла
with open("book.pkl", "rb") as f:
book = pickle.load(f)

print(book.title) # Clean Code
print(book.author.name) # Robert C. Martin

🔍 Важно:

pickle сам восстанавливает вложенные объекты — и это его суперсила 💪

🤡 Немного юмора:

Десериализация — это как магия: ты шепчешь "load", и объект возвращается из цифрового небытия. Главное — чтобы его не звали Voldemort.
Сериализация и десериализация в Python: просто, мощно, с пояснениями. Уроки программирования Python для новичков
Сериализация и десериализация в Python: просто, мощно, с пояснениями. Уроки программирования Python для новичков