10.1 Все будет по-моему!

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

Чтобы сериализация работала и в таких случаях, придумали дать классу возможность самому управлять своей сериализацией. Для этого используются специальные методы: __reduce__(), __getstate__(), __setstate__(). Эти методы позволяют указать, как объекты должны быть сериализованы и восстановлены.

Основные методы управляемой сериализации:

  • __reduce__(): Указывает, как объект должен быть сериализован.
  • __getstate__(): Возвращает состояние объекта для сериализации.
  • __setstate__(self, state): Восстанавливает объект из состояния.

Ниже я расскажу о них подробнее, и как их вместе использовать.

10.2 Метод __reduce__()

Метод __reduce__() возвращает кортеж, который указывает, как объект должен быть сериализован и десериализован. Кортеж обычно содержит:

  • Ссылку на функцию или класс, который будет использоваться для восстановления объекта.
  • Кортеж аргументов для этой функции или класса.
  • Дополнительное состояние объекта (если необходимо).

Пример:


import pickle

class CustomClass:
    def __init__(self, value):
        self.value = value
            
    def __reduce__(self):
        return (self.__class__, (self.value,))
            
    def __repr__(self):
        return f"CustomClass(value={self.value})"
            
# Создание объекта
obj = CustomClass(42)
            
# Сериализация объекта
serialized_obj = pickle.dumps(obj)
print("Сериализованный объект:", serialized_obj)
            
# Десериализация объекта
deserialized_obj = pickle.loads(serialized_obj)
print("Десериализованный объект:", deserialized_obj)

По умолчанию функция __reduce__() имеет такое поведение:


class CustomClass:
    def __init__(self, value):
        self.value = value
        
    def __reduce__(self):
        # Определение класса
        cls = self.__class__
        # Аргументы конструктора
        args = (self.value,)
        # Состояние объекта
        state = self.__dict__
        return (cls, args, state)

Она возвращает кортеж, состоящий из трёх объектов:

  • Ссылка на текущий класс
  • Аргументы конструктора (кортеж)
  • Ссылка на текущее состояние объекта

Если вас такое поведение устраивает — __reduce__() можете не переопределять.

10.3 Чтение и запись состояния

Методы __getstate__() и __setstate__()

Эти методы используются для управления состоянием объекта во время сериализации и десериализации.

  • __getstate__(): Возвращает состояние объекта, которое должно быть сериализовано.
  • __setstate__(self, state): Восстанавливает объект из состояния.

Пример:

Допустим, мы хотим сохранить не все поля объекта, а исключить некоторые из них. Для этого в методе __getstate__() нужно:

  1. Скопировать текущее состояние объекта (заданное служебным полем __dict__) в отдельную переменную — словарь state.
  2. Удалить из неё все поля, которые не нужно сериализовать.
  3. Вернуть полученный объект как результат функции __getstate__().

import pickle

class CustomClass:
    def __init__(self, value):
        self.value = value
        self.internal_state = "internal"
            
    def __getstate__(self):
        state = self.__dict__.copy()
        del state['internal_state']  # Исключаем внутреннее состояние
        return state
            
    def __setstate__(self, state):
        self.__dict__.update(state)
        self.internal_state = "restored internal"  # Восстанавливаем внутреннее состояние
            
    def __repr__(self):
        return f"CustomClass(value={self.value}, internal_state={self.internal_state})"
            
# Создание объекта
obj = CustomClass(42)
print("Оригинальный объект:", obj)
            
# Сериализация объекта
serialized_obj = pickle.dumps(obj)
print("Сериализованный объект:", serialized_obj)
            
# Десериализация объекта
deserialized_obj = pickle.loads(serialized_obj)
print("Десериализованный объект:", deserialized_obj)

При десериализации, в функции __setstate__(), мы делаем две вещи:

  1. Обновляем текущее состояние объекта с помощью метода update().
  2. Поле internal_state (и другие несериализуемые поля) получают новые значения.
undefined
2
Задача
Модуль 1: Python Core, 12 уровень, 9 лекция
Недоступна
Использованиее метода reduce()
Использованиее метода reduce()
undefined
2
Задача
Модуль 1: Python Core, 12 уровень, 9 лекция
Недоступна
Исключение несериализуемых полей
Исключение несериализуемых полей
undefined
1
Опрос
Работа с директориями,  12 уровень,  9 лекция
недоступен
Работа с директориями
Работа с директориями