Why can't pickle dump this instance?

J

Jane Austine

Hi.

class A:
def __init__(self,tick):
if tick:
self.foo=self.bar
else:
self.foo=self.bur
def bar(self):
print 'bar'
def bur(self):
print 'bur'

import pickle
pickle.dumps(A())

running this script results in "TypeError: can't pickle function objects"

Why does this happen? and what can I do?

Jane
 
T

Thomas D'Tak

class A:
def __init__(self,tick):
if tick:
self.foo=self.bar
else:
self.foo=self.bur
def bar(self):
print 'bar'
def bur(self):
print 'bur'

import pickle
pickle.dumps(A())

running this script results in "TypeError: can't pickle function objects"

Why does this happen? and what can I do?

Running this script should actually result in

TypeError: __init__() takes exactly 2 arguments (1 given)

because you did not write

def __init__(self, tick=None):


But coming back to your original problem, have a look at the
following code:

def bar():
print 'bar'

def bur():
print 'bur'

class A:
def __init__(self,tick=None):
if tick:
self.foo=bar
else:
self.foo=bur

import pickle
pickle.dumps(A())

The above will do what you want. Have a look at the Python
Library Reference's

3.14.4 What can be pickled and unpickled?
http://www.python.org/doc/2.3.4/lib/node65.html

to see, why this works while the other script does not.

HTH, Th.
 
P

Peter Otten

Jane said:
class A:
def __init__(self,tick):
if tick:
self.foo=self.bar
else:
self.foo=self.bur
def bar(self):
print 'bar'
def bur(self):
print 'bur'

import pickle
pickle.dumps(A())

running this script results in "TypeError: can't pickle function objects"

Why does this happen? and what can I do?

By default pickle bypasses the __init__() method completely, it just saves
class name and the instance's __dict__. In your case __dict__ happens to
contain a bound method which cannot be pickled. I don't know why, maybe the
general case where the instance the method is bound to could be a different
object would get too messy.

The normal way to manipulate the state to be pickled/unpickled is to
implement the __getstate__()/__setstate__() pair, but in your case it is
easier to trigger invocation of __init__() by generating the appropriate
argument list via __getinitargs__().

Peter

<code>
import pickle

class A:
def __init__(self, tick):
if tick:
self.foo = self.bar
else:
self.foo = self.bur

def __getstate__(self):
# copy the __dict__ so that further changes
# do not affect the current instance
d = dict(self.__dict__)
# remove the closure that cannot be pickled
del d["foo"]
# return state to be pickled
return d

def __getinitargs__(self):
tick = self.foo == self.bar
# return argument tuple for __init__()
# all items must be pickleable
return (tick,)

def bar(self):
print "bar"
def bur(self):
print "bur"

if __name__ == "__main__":
# test it
for tick in [False, True]:
print "\ntick =", tick
a = A(tick)
a.foo()
s = pickle.dumps(a)
b = pickle.loads(s)
b.foo()
</code>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,143
Latest member
DewittMill
Top