Ответ 1
Используйте бинарный протокол для вашего выбора (вместо старого ASCII, который вы по умолчанию используете), и все будет в порядке. Обратите внимание:
>>> class ws(object):
... __slots__ = 'a', 'b'
... def __init__(self, a=23, b=45): self.a, self.b = a, b
...
>>> x = ws()
>>> import pickle
>>> pickle.dumps(x, -1)
'\x80\x02c__main__\nws\nq\x00)\x81q\x01N}q\x02(U\x01aq\x03K\x17U\x01bq\x04K-u\x86q\x05b.'
>>> pickle.dumps(x)
Traceback (most recent call last):
[[snip]]
File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/copy_reg.py", line 77, in _reduce_ex
raise TypeError("a class that defines __slots__ without "
TypeError: a class that defines __slots__ without defining __getstate__ cannot be pickled
>>>
Как видите, протокол -1
(что означает "самый лучший, самый быстрый и самый компактный протокол") работает просто отлично, в то время как протокол по умолчанию 0
(старый протокол ascii, разработанный для обеспечения совместимости на всех этапах назад до Python 1.5 и более ранних версий) - это именно то исключение, которое вы наблюдали.
Кроме того, -1
будет быстрее и даст более компактные результаты - вам просто нужно убедиться, что вы правильно сохраняете и восстанавливаете двоичные строки, которые он генерирует (например, если вы выбираете файл, обязательно откройте последний для wb
, а не только для w
).
Если по какой-либо причине это универсальное решение не доступно для вас, есть хаки и приемы (например, подкласс pickle.Pickler
, используйте непосредственно экземпляр вашего подкласса, а не базовый, как это делает pickle.dumps
), переопределите save
, так что он отслеживает type(obj)
перед делегированием суперклассу), но при обновлении до самого современного, самого современного протокола (-1
гарантированно будет в любой данной версии Python самым продвинутым). эта версия поддерживает) было бы хорошей идеей в любом случае, если это вообще возможно.