473,407 Members | 2,598 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,407 software developers and data experts.

Persist a class (not an instance)

Is there a way to persist a class definition (not a class instance, the actual class) so it can be restored later? A naive approach using pickle doesn't work:
import pickle
class Foo(object): ... def show(self):
... print "I'm a Foo"
... p = pickle.dumps(Foo)
p 'c__main__\nFoo\np0\n.'

Hmm, doesn't look too promising. In a new interpreter:
import pickle
p='c__main__\nFoo\np0\n.'
Foo = pickle.loads(p)

Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "C:\Python24\lib\pickle.py", line 1394, in loads
return Unpickler(file).load()
File "C:\Python24\lib\pickle.py", line 872, in load
dispatch[key](self)
File "C:\Python24\lib\pickle.py", line 1104, in load_global
klass = self.find_class(module, name)
File "C:\Python24\lib\pickle.py", line 1140, in find_class
klass = getattr(mod, name)
AttributeError: 'module' object has no attribute 'Foo'

The idea is to persist classes that are created and modified at runtime.

Thanks,
Kent
Nov 25 '05 #1
6 1413
Kent Johnson enlightened us with:
Is there a way to persist a class definition (not a class instance,
the actual class) so it can be restored later?


From the docs:

"Similarly, classes are pickled by named reference, so the same
restrictions in the unpickling environment apply. Note that none of
the class's code or data is pickled [...]"

Sybren
--
The problem with the world is stupidity. Not saying there should be a
capital punishment for stupidity, but why don't we just take the
safety labels off of everything and let the problem solve itself?
Frank Zappa
Nov 25 '05 #2
Sybren Stuvel wrote:
Kent Johnson enlightened us with:
Is there a way to persist a class definition (not a class instance,
the actual class) so it can be restored later?

From the docs:

"Similarly, classes are pickled by named reference, so the same
restrictions in the unpickling environment apply. Note that none of
the class's code or data is pickled [...]"


OK that confirms that pickle won't work. Is there another approach that will?

Kent
Nov 25 '05 #3
Kent Johnson enlightened us with:
OK that confirms that pickle won't work. Is there another approach
that will?


Well, since the classes are created at runtime as well, you could
compile them using the appropriate API and call exec() on them.

Sybren
--
The problem with the world is stupidity. Not saying there should be a
capital punishment for stupidity, but why don't we just take the
safety labels off of everything and let the problem solve itself?
Frank Zappa
Nov 25 '05 #4
Kent Johnson <ke****@tds.net> wrote:
Is there a way to persist a class definition (not a class instance, the
actual class) so it can be restored later? A naive approach using pickle
doesn't work:


You can use copy_reg to customize pickling behavior. In this case,
you'd need a custom metaclass to use as the type for your "picklable
classes". Moreover, if the class has attributes that you also want to
pickle, such as methods or properties, you'll have to arrange for custom
pickling of *them*, too. So, yes, there are ways, but not simple ones.
Alex
Nov 25 '05 #5
Kent Johnson wrote:
Is there a way to persist a class definition (not a class instance,
the actual class) so it can be restored later? A naive approach
using pickle doesn't work: [snip] The idea is to persist classes that are created and modified at runtime.


I couldn't resist the challenge, so I decided to take a crack at it. My
code is below. (I hope it's OK to post it even though it's a bit on the
long side.) So far, it seems to work OK; the biggest caveat to be aware
of is that functions' global context is not preserved.

My approach was to use pickle's __reduce__ protocol to store functions
and classes. Of course, you can't modify the built-in function and
classobj types, so I subclassed Pickler to override them. The advantage
of this is that you don't need an extension to the pickling data
format, and you can use the standard unpickler. (The custom module
still needs to have been imported, as it adds the classobj type to
__builtins__.)

Unfortunately, I'm not sure how to go about making it work for
new-style classes. It would seem to involve messing with dictproxy and
descriptor objects, and that's getting me into more unfamiliar
territory.

I'm sure there's a better way to do this; this seemed like "the
simplest thing that could possibly work".

-- David

################################################## ###
# code_pickle.py

import sys, copy_reg, pickle, new, marshal, types, StringIO

# Needed to unserialize old-style classes
sys.modules['__builtin__'].classobj = new.classobj

# from http://aspn.activestate.com/ASPN/Coo.../Recipe/439096
def get_cell_value(cell):
return type(lambda: 0)(
(lambda x: lambda: x)(0).func_code, {}, None, None, (cell,)
)()

def func_constructor(name, code, defaults, closure):
return new.function(marshal.loads(code), globals(), name,
defaults, closure)

class CodePickler(pickle.Pickler):
def __init__(self, *args, **kwargs):
pickle.Pickler.__init__(self, *args, **kwargs)
self.dispatch = self.dispatch.copy()
self.dispatch[types.ClassType] = CodePickler.do_class
self.dispatch[types.FunctionType] = CodePickler.do_function

def save(self, ob, *args, **kwargs):
print ob
pickle.Pickler.save(self, ob, *args, **kwargs)

def do_class(self, ob):
if ob in (types.__dict__.values()):
self.save_global(ob)
else:
args = (ob.__name__, ob.__bases__, ob.__dict__)
self.save_reduce(type(ob), args)

def do_function(self, ob):
if ob == func_constructor:
self.save_global(ob)
else:
if ob.func_closure:
closure = tuple(map(get_cell_value, ob.func_closure))
else:
closure = None
args = (ob.func_name, marshal.dumps(ob.func_code),
ob.func_defaults, closure)
self.save_reduce(func_constructor, args)

def dumps(ob):
s = StringIO.StringIO()
CodePickler(s).dump(ob)
return s.getvalue()

# Example:
#
# import code_pickle
# class Foo:
# def show(self):
# print "Foo!"
#
# s = code_pickle.dumps(Foo)
# --------------------------------------
# import code_pickle, pickle
# Foo = pickle.loads(s)
# Foo().show
################################################## ###

Nov 25 '05 #6

David Wahler wrote:
Kent Johnson wrote:
Is there a way to persist a class definition (not a class instance,
the actual class) so it can be restored later? A naive approach
using pickle doesn't work:

[snip]
The idea is to persist classes that are created and modified at runtime.


I couldn't resist the challenge, so I decided to take a crack at it. My
code is below. (I hope it's OK to post it even though it's a bit on the
long side.) So far, it seems to work OK; the biggest caveat to be aware
of is that functions' global context is not preserved.

My approach was to use pickle's __reduce__ protocol to store functions
and classes. Of course, you can't modify the built-in function and
classobj types, so I subclassed Pickler to override them. The advantage
of this is that you don't need an extension to the pickling data
format, and you can use the standard unpickler. (The custom module
still needs to have been imported, as it adds the classobj type to
__builtins__.)

Unfortunately, I'm not sure how to go about making it work for
new-style classes. It would seem to involve messing with dictproxy and
descriptor objects, and that's getting me into more unfamiliar
territory.

I'm sure there's a better way to do this; this seemed like "the
simplest thing that could possibly work".


This is actually pretty sweet. It seems to me that you'll be fine with
new-style classes if you just save dict(ob.__dict__) instead of trying
to save __dict__ directly, as that'll get rid of the dictproxy part.
There's no generic way to save descriptors, as far as I know, but you
can always register reducers for specific types, like property, and
user-defined descriptor classes are likely to be picklable anyway.

As for functions' global context, you could look to see if there's a
__name__ present, in which case you can save a reference to that
module's __dict__. Otherwise, simply pickle the func_globals as-is.
Some folks might just want to do that anyway, if the code isn't
actually being loaded from a module.

Of course, the classic caveat regarding pickles and security applies to
all this. That is, pickles and security don't mix. If you want one,
you can't really get the other. ;-)

Nov 26 '05 #7

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
by: BH | last post by:
I developed a small web app using the FormsAuthentication class to set a cookie (FormsAuthentication.SetAuthCookie(value, isPersist)). The cookie persists fine on my local PC when "isPersist" is...
1
by: Paul Perot | last post by:
Hi All: I have a DataTable that I have defined Globally. I populate this datatable dynamically with file/folder information that I read directly from the server. I use this datatable...
1
by: magister | last post by:
hello I am putting together a web form which builds an xml file. I have another class which is referenced in the asp.net page. The first page load creates an instance of the class. In the class...
0
by: Jeremy Chapman | last post by:
I have included below virtually all the code to a control I'm trying to build. My issue is that an array list property in my control does not get persisted properly to the aspx page code in design...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.