29

定義した(新しいスタイルの)クラスのオブジェクトをピクルスにしようとしています。しかし、次のエラーが発生します。

>>> 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の優れた回答を受け入れている間は、オブジェクト参照を「共有」するためにピクルスにするのとは異なる戦略を追求する必要があります。

4

3 に答える 3

31

定義する__slots__(ではなく__getstate__)クラスは、直接または間接的に、あなたの祖先クラス、またはあなたの属性またはアイテムのクラス(または祖先クラス)のいずれかです。基本的に、参照の有向グラフ内の任意のオブジェクトのクラスピクルスはグラフ全体を保存する必要があるため、オブジェクトをルートとして使用します。

あなたの悩みの種に対する簡単な解決策は、プロトコルを使用することです-1。これは、「ピクルスが使用できる最高のプロトコル」を意味します。__slots__デフォルトは、 vsについてこの制限を課す古代のASCIIベースのプロトコルです__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文字列ではなく、バイナリ文字列/ファイルを生成します。結果として得られるpickle化されたファイルは、十分に古いバージョンのPythonではロードできません。__slots__重要な点に加えて、よりコンパクトな結果とより優れたパフォーマンスなどの利点があります。

デフォルトのプロトコルを使用せざるを得ない場合は、問題を引き起こしているクラスとその理由を正確に特定する必要があります。これが当てはまる場合は戦略について話し合うことができます(ただし、-1プロトコルを使用できる可能性がある場合は、話し合う価値がないほど優れています;-)そして厄介なクラス/オブジェクトを探す単純なコード検査は複雑すぎることがわかります(私は疑問に思っている場合に備えて、グラフ全体の使用可能な表現を取得するために、いくつかのディープコピーベースのトリックに注意してください)。

于 2010-02-05T02:35:10.907 に答える
6

おそらく、インスタンスの属性が使用しています__slots__

たとえば、漬け物ができないようにsocket持っています__slots__

エラーの原因となっている属性を特定し、独自の属性を記述して、その属性を無視する必要が __getstate__あり__setstate__ます

于 2010-02-05T00:06:34.240 に答える
2

PEP 307から:

この__getstate__メソッドは、オブジェクト自体を参照せずに、オブジェクトの状態を表す選択可能な値を返す必要があります。メソッドが存在しない場合__getstate__は、を返すデフォルトの実装が使用されますself.__dict__

于 2010-02-05T00:04:26.280 に答える