How to make a custom exception class with multiple init args pickleable

前端 未结 4 1402
醉梦人生
醉梦人生 2021-01-31 02:46

Why does my custom Exception class below not serialize/unserialize correctly using the pickle module?

import pickle

class MyException(Exception):
    def __ini         


        
相关标签:
4条回答
  • 2021-01-31 03:25

    The current answers break down if you're using both arguments to construct an error message to pass to the parent Exception class. I believe the best way is to simply override the __reduce__ method in your exception. The __reduce__ method should return a two item tuple. The first item in the tuple is your class. The second item is a tuple containing the arguments to pass to your class's __init__ method.

    import pickle
    
    class MyException(Exception):
        def __init__(self, arg1, arg2):
            self.arg1 = arg1
            self.arg2 = arg2
    
            super(MyException, self).__init__('arg1: {}, arg2: {}'.format(arg1, arg2))
    
        def __reduce__(self):
            return (MyException, (self.arg1, self.arg2))
    
    
    original = MyException('foo', 'bar')
    print repr(original)
    print original.arg1
    print original.arg2
    
    reconstituted = pickle.loads(pickle.dumps(original))
    print repr(reconstituted)
    print reconstituted.arg1
    print reconstituted.arg2
    

    More info about __reduce__ here.

    0 讨论(0)
  • 2021-01-31 03:39

    I like Martijn's answer, but I think a better way is to pass all arguments to the Exception base class:

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

    The base Exception class' __reduce__ method will include all the args. By not making all of the extra arguments optional, you can ensure that the exception is constructed correctly.

    0 讨论(0)
  • 2021-01-31 03:43

    I simply do this

    class MyCustomException(Exception):
        def __init__(self):
            self.value = 'Message about my error'
    
        def __str__(self):
            return repr(self.value)
    
    ... somewhere in code ...
    raise MyCustomException
    
    0 讨论(0)
  • 2021-01-31 03:47

    Make arg2 optional:

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

    The base Exception class defines a .__reduce__() method to make the extension (C-based) type picklable and that method only expects one argument (which is .args); see the BaseException_reduce() function in the C source.

    The easiest work-around is making extra arguments optional. The __reduce__ method also includes any additional object attributes beyond .args and .message and your instances are recreated properly:

    >>> 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'
    
    0 讨论(0)
提交回复
热议问题