Я пытаюсь засолить объект (новый стиль) класс, который я определил. Но я получаю следующую ошибку:
>>> 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, я оказываюсь перед необходимостью преследовать другую стратегию, чем соление, чтобы "совместно использовать" ссылку на объект.
Класс, определяющий __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
, то это намного лучше, что не стоит обсуждать;-), а простая проверка кода в поисках проблемного класса/объекта оказывается слишком сложной (я имею в виду некоторые трюки, основанные на глубоком скопировании, чтобы получить удобное представление всего графа, если вам интересно).
Из PEP 307 :
Метод
__ getstate __
должен возвращать выбираемое значение представление состояния объекта без ссылки на сам объект . Если метод__ getstate __
не существует, используется реализация по умолчанию , которая возвращаетself .__ dict __
.
Возможно, атрибут вашего экземпляра использует __ slots __
Например, сокет
имеет __ slots __
, поэтому его нельзя мариновать
Вам необходимо идентифицировать какой атрибут вызывает ошибку, и напишите свои собственные
__ getstate __
и __ setstate __
, чтобы игнорировать этот атрибут