Почему я получаю ошибку о своем определении класса __ слоты __ при попытке засолить объект?

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

>>> 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, я оказываюсь перед необходимостью преследовать другую стратегию, чем соление, чтобы "совместно использовать" ссылку на объект.

28
задан Community 23 May 2017 в 10:30
поделиться

3 ответа

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

Простым решением вашего запроса является использование протокола -1, что означает "лучшая протокольная пикуль"; по умолчанию это древний протокол, основанный на ASCII, который накладывает это ограничение на __slots__ vs __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 принимает __слоты__ в шаге, в то время как протокол по умолчанию дает то же самое исключение, которое вы видели.

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

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

31
ответ дан 28 November 2019 в 03:34
поделиться

Из PEP 307 :

Метод __ getstate __ должен возвращать выбираемое значение представление состояния объекта без ссылки на сам объект . Если метод __ getstate __ не существует, используется реализация по умолчанию , которая возвращает self .__ dict __ .

2
ответ дан 28 November 2019 в 03:34
поделиться

Возможно, атрибут вашего экземпляра использует __ slots __

Например, сокет имеет __ slots __ , поэтому его нельзя мариновать

Вам необходимо идентифицировать какой атрибут вызывает ошибку, и напишите свои собственные __ getstate __ и __ setstate __ , чтобы игнорировать этот атрибут

6
ответ дан 28 November 2019 в 03:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: