42

以下のカスタム Exception クラスが pickle モジュールを使用して正しくシリアライズ/アンシリアライズしないのはなぜですか?

import pickle

class MyException(Exception):
    def __init__(self, arg1, arg2):
        self.arg1 = arg1
        self.arg2 = arg2

        super(MyException, self).__init__(arg1)

e = MyException("foo", "bar")

str = pickle.dumps(e)
obj = pickle.loads(str)

このコードは、次のエラーをスローします。

Traceback (most recent call last):
File "test.py", line 13, in <module>
   obj = pickle.loads(str)
File "/usr/lib/python2.7/pickle.py", line 1382, in loads
   return Unpickler(file).load()
File "/usr/lib/python2.7/pickle.py", line 858, in load
   dispatch[key](self)
File "/usr/lib/python2.7/pickle.py", line 1133, in load_reduce
   value = func(*args)
TypeError: __init__() takes exactly 3 arguments (2 given)

この問題は、クラスをピクルフレンドリーにする方法に関する私の知識不足に起因していると確信しています。興味深いことに、この問題は、クラスが Exception を継承していない場合には発生しません。

助けてくれてありがとう。カイル

編集:shx2ごとにスーパーへの呼び出しを修正する編集:タイトル/コンテンツのクリーンアップ

4

5 に答える 5

40

オプションarg2にする:

class MyException(Exception):
    def __init__(self, arg1, arg2=None):
        self.arg1 = arg1
        self.arg2 = arg2
        super(MyException, self).__init__(arg1)

基本Exceptionクラスは、拡張 (C ベース) 型を picklable にする.__reduce__()メソッドを定義し、そのメソッドは1 つの引数 (つまり.args) のみを想定しています。BaseException_reduce()C ソースの関数を参照してください。

最も簡単な回避策は、追加の引数をオプションにすることです。この__reduce__メソッドには、 および以外の追加のオブジェクト属性含まれており、インスタンスが適切に再作成されます。.args.message

>>> e = MyException('foo', 'bar')
>>> e.__reduce__()
(<class '__main__.MyException'>, ('foo',), {'arg1': 'foo', 'arg2': 'bar'})
>>> pickle.loads(pickle.dumps(e))
MyException('foo',)
>>> e2 = pickle.loads(pickle.dumps(e))
>>> e2.arg1
'foo'
>>> e2.arg2
'bar'
于 2013-04-26T21:02:58.170 に答える
16

私はMartijnの答えが好きですが、より良い方法はすべての引数をException基本クラスに渡すことだと思います:

class MyException(Exception):
    def __init__(self, arg1, arg2):
        super(MyException, self).__init__(arg1, arg2)        
        self.arg1 = arg1
        self.arg2 = arg2

基本Exceptionクラスの__reduce__メソッドにはすべての引数が含まれます。追加の引数をすべてオプションにしないことで、例外が正しく構築されるようにすることができます。

于 2014-12-06T16:51:36.167 に答える