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__() потрібно:
- Скопіювати поточний стан об'єкта (задане службовим полем
__dict__) в окрему змінну — словникstate. - Видалити з нього всі поля, які не потрібно серіалізувати.
- Повернути отриманий об'єкт як результат функції
__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__(), ми робимо дві речі:
- Оновлюємо поточний стан об'єкта за допомогою методу
update(). - Поле
internal_state(і інші несеріалізовані поля) отримують нові значення.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ