Иногда пользовательские таблицы диспетчеризации Pickler.dispatch_table()
может быть недостаточно гибким. Например, что если необходимо настроить выборку на основе другого критерия, нежели тип объекта или сделать выборку функций и классов по именам.
В этих случаях можно создать подкласс из класса pickle.Pickler()
и реализовать метод Pickler.reducer_override()
. Этот метод может вернуть произвольный кортеж __Reduce__()
. В качестве альтернативы он может возвращать NotImplemented
вместо традиционного поведения.
В случае если определены как Pickler.dispatch_table()
, так и Pickler.reducer_override()
, то метод reducer_override()
имеет приоритет.
Примечание.
По соображениям производительности Pickler.reducer_override()
нельзя вызывать для следующих объектов: None
, True
, False
и точных экземпляров int
, float
, bytes
, str
, dict
, set
, frozenset
, list
и tuple
.
Вот простой пример, где разрешается сохранять и восстанавливать определенный класс:
# Python 3.8 и выше import io import pickle class TestClass: my_attribute = 1 class MyPickler(pickle.Pickler): def reducer_override(self, obj): """Custom reducer for TestClass.""" if getattr(obj, "__name__", None) == "TestClass": return type, (obj.__name__, obj.__bases__, {'my_attribute': obj.my_attribute}) else: # Для любого другого объекта, переход # на обычное сокращение return NotImplemented f = io.BytesIO() p = MyPickler(f) p.dump(TestClass) del TestClass unpickled_class = pickle.loads(f.getvalue()) assert isinstance(unpickled_class, type) assert unpickled_class.__name__ == "TestClass" assert unpickled_class.my_attribute == 1