2010-02-05 1 views
24

Я пытаюсь разжечь объект класса (нового стиля), который я определил. Но я получаю следующее сообщение об ошибке:Почему у меня возникает ошибка в моем классе, определяющем __slots__ при попытке рассортировать объект?

>>> with open('temp/connection.pickle','w') as f: 
... pickle.dump(c,f) 
... 
Traceback (most recent call last): 
    File "<stdin>", line 2, in <module> 
    File "/usr/lib/python2.5/pickle.py", line 1362, in dump 
    Pickler(file, protocol).dump(obj) 
    File "/usr/lib/python2.5/pickle.py", line 224, in dump 
    self.save(obj) 
    File "/usr/lib/python2.5/pickle.py", line 331, in save 
    self.save_reduce(obj=obj, *rv) 
    File "/usr/lib/python2.5/pickle.py", line 419, in save_reduce 
    save(state) 
    File "/usr/lib/python2.5/pickle.py", line 286, in save 
    f(self, obj) # Call unbound method with explicit self 
    File "/usr/lib/python2.5/pickle.py", line 649, in save_dict 
    self._batch_setitems(obj.iteritems()) 
    File "/usr/lib/python2.5/pickle.py", line 663, in _batch_setitems 
    save(v) 
    File "/usr/lib/python2.5/pickle.py", line 306, in save 
    rv = reduce(self.proto) 
    File "/usr/lib/python2.5/copy_reg.py", line 76, in _reduce_ex 
    raise TypeError("a class that defines __slots__ without " 
TypeError: a class that defines __slots__ without defining __getstate__ cannot be pickled 

Я не явно определить __slots__ в моем классе. Что-то я неявно определяю? Как мне обойти это? Мне нужно определить __getstate__?

Обновление:gnibbler выбрал хороший пример. Класс объекта, который я пытаюсь раскрыть, обертывает сокет. (Теперь мне кажется, что) гнезда определяют __slots__, а не __getstate__. Я предполагаю, что, как только процесс завершится, другой процесс не может распасться и использовать соединение сокета предыдущего процесса. Поэтому, пока я принимаю превосходный ответ Alex Martelli, мне придется проводить другую стратегию, чем травление, чтобы «поделиться» ссылкой на объект.

+1

Можете ли вы показать код из класса? Вероятно, нам не нужно видеть * все * методы. –

ответ

26

Класс, определяющий __slots__ (а не __getstate__), может быть либо вашим классом-предком, либо классом (или классом предка) вашего атрибута или вашего элемента, прямо или косвенно: по существу, класс любого объекта в ориентированный граф ссылок с вашим объектом как root, так как травление необходимо сохранить весь граф.

Простым решением вашего затруднительного положения является использование протокола -1, что означает, что «наилучший протокол может использовать протокол»; по умолчанию используется старинный протокол на основе ASCII, который накладывает это ограничение на __slots__ против __getstate__. Рассмотрим:

>>> class sic(object): 
... __slots__ = 'a', 'b' 
... 
>>> import pickle 
>>> pickle.dumps(sic(), -1) 
'\x80\x02c__main__\nsic\nq\x00)\x81q\x01.' 
>>> pickle.dumps(sic()) 
Traceback (most recent call last): 
    [snip snip] 
    raise TypeError("a class that defines __slots__ without " 
TypeError: a class that defines __slots__ without defining __getstate__ cannot be pickled 
>>> 

Как вы видите, протокол -1 принимает __slots__ в шаге, в то время как протокол по умолчанию дает тот же исключение увидели.

Проблемы с протоколом -1: он создает двоичную строку/файл, а не ASCII, такой как протокол по умолчанию; полученный маринованный файл не будет загружаться достаточно древними версиями Python. К преимуществам, помимо ключевого, относятся __slots__, включают более компактные результаты и лучшую производительность.

Если вы вынуждены использовать протокол по умолчанию, вам нужно будет точно определить, какой класс дает вам проблемы и почему именно. Мы можем обсудить стратегии, если это так (но если вы, возможно, используете протокол -1, это намного лучше, что не стоит обсуждать ;-) и простая проверка кода, которая ищет сложный класс/объект, оказывается слишком сложной (у меня есть имея в виду некоторые трюки на основе глубины, чтобы получить полезное представление всего графика, на случай, если вам интересно).

2

От PEP 307:

The __getstate__ method should return a picklable value representing the object's state without referencing the object itself. If no __getstate__ method exists, a default implementation is used that returns self.__dict__ .

6

Возможно атрибут экземпляра используется __slots__

Например, socket имеет __slots__ поэтому он не может быть маринованные

Вам нужно определить, какой атрибут вызывает ошибку и записывает ваши собственные __getstate__ и __setstate__, чтобы игнорировать этот атрибут

Смежные вопросы