This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Python exception object is different after pickle.dumps and pickle.loads
Type: behavior Stage: resolved
Components: Versions: Python 3.9
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: iritkatriel, rhettinger, yonghengzero
Priority: normal Keywords:

Created on 2021-09-06 10:14 by yonghengzero, last changed 2022-04-11 14:59 by admin.

Files
File name Uploaded Description Edit
screenshot.png yonghengzero, 2021-09-06 10:14
Messages (4)
msg401128 - (view) Author: Chen Zero (yonghengzero) Date: 2021-09-06 10:14
Hi, when I'm trying to serialize/deserialize python exception object through pickle, I found that deserialize result is not the same as the original object...

My python version is 3.9.1, working os: macOS Big Sur 11.4

Here is minimum reproducing code example:

import pickle

class ExcA(Exception):
    def __init__(self, want):
        msg = "missing "
        msg += want
        super().__init__(msg)

ExcA('bb')   # this will output ExcA("missing bb"), which is good
pickle.loads(pickle.dumps(ExcA('bb')))  # this will output ExcA("missing missing bb"), which is different from `ExcA('bb')`
msg401135 - (view) Author: Irit Katriel (iritkatriel) * (Python committer) Date: 2021-09-06 13:08
The default __reduce__ method of Exception returns the arg you pass to the Exception constructor:

>>> a = ExcA("a banana")
>>> a.__reduce__()
(<class '__main__.ExcA'>, ('missing a banana',))
>>> 


This is then pickled, and when unpickled the arg is passed to the ExcA constructor. 

If you want to change this, you can implement __reduce__ on ExcA o return just the part you want it to return.
msg401137 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2021-09-06 14:28
Pickling customized subclasses can be tricky.  The essential details are here:  https://docs.python.org/3/library/pickle.html#object.__reduce__

Here's some code to get you started.

class ExcA(Exception):
    def __init__(self, want):
        msg = "missing "
        msg += want
        super().__init__(msg)
    def __reduce__(self):
        return (type(self), self.args, self.args)
    def __setstate__(self, state):
        self.args = stat
msg401153 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2021-09-06 16:40
It would be nice if exception pickling was more friendly to subclasses.  Perhaps, the default should be to store and restore all state including args and a __dict__ if any.
History
Date User Action Args
2022-04-11 14:59:49adminsetgithub: 89275
2021-09-06 16:40:31rhettingersetmessages: + msg401153
2021-09-06 14:49:30rhettingersetstatus: closed -> open
resolution: not a bug ->
2021-09-06 14:28:37rhettingersetstatus: open -> closed
resolution: not a bug
stage: resolved
2021-09-06 14:28:21rhettingersetnosy: + rhettinger
messages: + msg401137
2021-09-06 13:08:03iritkatrielsetnosy: + iritkatriel
messages: + msg401135
2021-09-06 10:15:25yonghengzerosettitle: Python exception object is different after pickle.loads and pickle.dumps -> Python exception object is different after pickle.dumps and pickle.loads
2021-09-06 10:14:34yonghengzerocreate