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
(і інші несеріалізовані поля) отримують нові значення.