Hi,
I am puzzled why Python's exception classes don't seem to follow the pickle
protocol.
To be more specific: an instance of a user defined exception, subclassed from Exception,
cannot be pickled/unpickled correctly in the expected way.
The pickle protocol says that:
__getinitargs__ is used if you want __init__ to be called for old-style classes
__getnewargs__ is used if you want to pass params to __new__ for new-style
classes
__getstate__ is used to determine what to pickle instead of the objects __dict__
None of these are used when pickling Exception objects!
I've pasted some test code at the end of this message that creates a normal object and
an object derived from Exception, and pickles them both. Then it unpickles them.
The output is:
creating MyObj
myobj init: bla
creating MyEx
myex init: foutje
pickle myobj
myobj getnewargs # <-- great, newargs is used because of new style class
myobj getstate # getstate as well
pickle myex
unpickling MyObj # <-- huh?? where are getnewargs/getinitargs/getstate?
unpickled MyObj: [MyObj 'bla']
unpickling MyEx
Traceback (most recent call last):
File "ex.py", line 49, in <module>
o=pickle.loads(p_myex)
TypeError: ('__init__() takes exactly 2 arguments (1 given)', <class
'__main__.MyEx'>, ())
So there are 2 problems: the pickle protocol isn't used when exception objects (or
instances of classes derived from Exception) are pickled, and during unpickling, it then
crashes because it calls __init__ with the wrong amount of parameters. (why is it
bothering with __init__ anyway? Aren't exceptions new style classes?)
This started happening in Python 2.5, Python 2.4 works without error.
What is causing this? How can I best solve this error?
(using pickle instead of cPickle and changing the protocol number doesn't help).
--irmen
~~~~code follows~~~~
import cPickle as pickle
class MyObj(object):
def __init__(self, mymessage):
print "myobj init:",mymessage
self.mymessage=mymessage
def __str__(self):
return "[MyObj '%s']" % self.mymessage
def __getinitargs__(self):
print "myobj getinitargs"
return (self.mymessage,)
def __getnewargs__(self):
print "myobj getnewargs"
return (self.mymessage,)
def __getstate__(self):
print "myobj getstate"
return {"mymessage":self.mymessage}
class MyEx(Exception):
def __init__(self, mymessage):
print "myex init:",mymessage
self.mymessage=mymessage
def __str__(self):
return "[MyEx '%s']" % self.mymessage
def __getinitargs__(self):
print "myex getinitargs"
return (self.mymessage,)
def __getnewargs__(self):
print "myex getnewargs"
return (self.mymessage,)
def __getstate__(self):
print "myex getstate"
return {"mymessage":self.mymessage}
print "creating MyObj"
myobj=MyObj("bla")
print "creating MyEx"
myex=MyEx("foutje")
print "pickle myobj"
p_myobj=pickle.dumps(myobj,protocol=pickle.HIGHEST_PROTOCOL)
print "pickle myex"
p_myex=pickle.dumps(myex,protocol=pickle.HIGHEST_PROTOCOL)
print "unpickling MyObj"
o=pickle.loads(p_myobj)
print "unpickled MyObj:",o
print "unpickling MyEx"
o=pickle.loads(p_myex)
print "unpickled MyEx:",o
--
http://mail.python.org/mailman/listinfo/python-list