Ошибка TypeE на pickle.load с классом, производным от SimpleNamespace

1

Рассмотрим этот код Python (версия 3.5):

import pickle
from types import SimpleNamespace

class MyClass1(list):
    def __init__(self, x):
        self.append(x)

class MyClass2(SimpleNamespace):
    def __init__(self, x):
        self.x = x

a0 = SimpleNamespace(x=99)
a1 = MyClass1(99)
a2 = MyClass2(99)

print('* SimpleNamespace:', pickle.loads(pickle.dumps(a0)))
print('* MyClass1:', pickle.loads(pickle.dumps(a1)))
print('* MyClass2:', pickle.loads(pickle.dumps(a2)))

Это отлично работает для первых двух (a0 и a1), но после обработки a2 я получаю сообщение об ошибке:

* SimpleNamespace: namespace(x=99)
* MyClass1: [99]
Traceback (most recent call last):
  File "./picktest.py", line 20, in <module>
    print('* MyClass2:', pickle.loads(pickle.dumps(a2)))
TypeError: __init__() missing 1 required positional argument: 'x'

Замечания:

  • SimpleNamespace можно мариновать.
  • Класс, полученный из другого типа (list), может быть (un) маринован.
  • Класс, полученный из SimpleNamespace не может быть разбросан, если он содержит аргументы __init__. (Ошибка возникает в pickle.loads)

Обратите внимание, что я попытался заменить self.x = x простым pass и это ничего не изменило.

Есть ли способ сделать эту работу иначе, чем переопределить MyClass2 без наследования?

Теги:
python-3.x
inheritance
pickle

1 ответ

1
Лучший ответ

Проблема в том, что SimpleNamespace определяет __reduce__, что pickle используется для unpickle вашего объекта. Однако __reduce__ определенный в SimpleNamespace, не соответствует вашему __init__. Вы можете определить свой собственный __reduce__ чтобы обойти вокруг этого:

import pickle
from types import SimpleNamespace

class MyClass1(list):

    def __init__(self, x):
        self.append(x)

class MyClass2(SimpleNamespace):

    def __init__(self, x):
        self.x = x

    def __reduce__(self):
        return (self.__class__, (self.x,))

a0 = SimpleNamespace(x=99)
a1 = MyClass1(99)
a2 = MyClass2(99)

print('* SimpleNamespace:', pickle.loads(pickle.dumps(a0))) 
print('* MyClass1:', pickle.loads(pickle.dumps(a1)))
print('* MyClass2:', pickle.loads(pickle.dumps(a2)))

Ещё вопросы

Сообщество Overcoder
Наверх
Меню