mirror of
https://github.com/python/cpython.git
synced 2025-09-27 10:50:04 +00:00
pickle classes; add format_version, load(s)/dump(s) shortcuts
This commit is contained in:
parent
cc08112ff4
commit
0c891ce61a
1 changed files with 61 additions and 16 deletions
|
@ -17,7 +17,7 @@ Unlike the built-in marshal module, pickle handles the following correctly:
|
||||||
|
|
||||||
- recursive objects
|
- recursive objects
|
||||||
- pointer sharing
|
- pointer sharing
|
||||||
- class instances
|
- classes and class instances
|
||||||
|
|
||||||
Pickle is Python-specific. This has the advantage that there are no
|
Pickle is Python-specific. This has the advantage that there are no
|
||||||
restrictions imposed by external standards such as CORBA (which probably
|
restrictions imposed by external standards such as CORBA (which probably
|
||||||
|
@ -62,7 +62,7 @@ define a method __getinitargs__ (XXX not a pretty name!), which should
|
||||||
return a *tuple* containing the arguments to be passed to the class
|
return a *tuple* containing the arguments to be passed to the class
|
||||||
constructor.
|
constructor.
|
||||||
|
|
||||||
Classes can influence how they are pickled -- if the class defines
|
Classes can influence how their instances are pickled -- if the class defines
|
||||||
the method __getstate__, it is called and the return state is pickled
|
the method __getstate__, it is called and the return state is pickled
|
||||||
as the contents for the instance, and if the class defines the
|
as the contents for the instance, and if the class defines the
|
||||||
method __setstate__, it is called with the unpickled state. (Note
|
method __setstate__, it is called with the unpickled state. (Note
|
||||||
|
@ -108,6 +108,7 @@ The following types can be pickled:
|
||||||
- strings
|
- strings
|
||||||
- tuples, lists and dictionaries containing only picklable objects
|
- tuples, lists and dictionaries containing only picklable objects
|
||||||
- class instances whose __dict__ or __setstate__() is picklable
|
- class instances whose __dict__ or __setstate__() is picklable
|
||||||
|
- classes
|
||||||
|
|
||||||
Attempts to pickle unpicklable objects will raise an exception
|
Attempts to pickle unpicklable objects will raise an exception
|
||||||
after having written an unspecified number of bytes to the file argument.
|
after having written an unspecified number of bytes to the file argument.
|
||||||
|
@ -125,12 +126,14 @@ the old value, not the modified one. (XXX There are two problems here:
|
||||||
I have no answers. Garbage Collection may also become a problem here.)
|
I have no answers. Garbage Collection may also become a problem here.)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__format_version__ = "1.0" # File format version
|
__version__ = "1.5" # Code version
|
||||||
__version__ = "1.4" # Code version
|
|
||||||
|
|
||||||
from types import *
|
from types import *
|
||||||
import string
|
import string
|
||||||
|
|
||||||
|
format_version = "1.1" # File format version we write
|
||||||
|
compatible_formats = ["1.0"] # Old format versions we can read
|
||||||
|
|
||||||
PicklingError = "pickle.PicklingError"
|
PicklingError = "pickle.PicklingError"
|
||||||
|
|
||||||
AtomicTypes = [NoneType, IntType, FloatType, StringType]
|
AtomicTypes = [NoneType, IntType, FloatType, StringType]
|
||||||
|
@ -153,6 +156,7 @@ TUPLE = 't'
|
||||||
LIST = 'l'
|
LIST = 'l'
|
||||||
DICT = 'd'
|
DICT = 'd'
|
||||||
INST = 'i'
|
INST = 'i'
|
||||||
|
CLASS = 'c'
|
||||||
GET = 'g'
|
GET = 'g'
|
||||||
PUT = 'p'
|
PUT = 'p'
|
||||||
APPEND = 'a'
|
APPEND = 'a'
|
||||||
|
@ -313,6 +317,14 @@ class Pickler:
|
||||||
self.write(BUILD)
|
self.write(BUILD)
|
||||||
dispatch[InstanceType] = save_inst
|
dispatch[InstanceType] = save_inst
|
||||||
|
|
||||||
|
def save_class(self, object):
|
||||||
|
d = id(object)
|
||||||
|
module = whichmodule(object)
|
||||||
|
name = object.__name__
|
||||||
|
self.write(CLASS + module + '\n' + name + '\n' +
|
||||||
|
PUT + `d` + '\n')
|
||||||
|
dispatch[ClassType] = save_class
|
||||||
|
|
||||||
|
|
||||||
classmap = {}
|
classmap = {}
|
||||||
|
|
||||||
|
@ -410,6 +422,20 @@ class Unpickler:
|
||||||
del self.stack[k:]
|
del self.stack[k:]
|
||||||
module = self.readline()[:-1]
|
module = self.readline()[:-1]
|
||||||
name = self.readline()[:-1]
|
name = self.readline()[:-1]
|
||||||
|
klass = self.find_class(module, name)
|
||||||
|
value = apply(klass, args)
|
||||||
|
self.stack.append(value)
|
||||||
|
dispatch[INST] = load_inst
|
||||||
|
|
||||||
|
def load_class(self):
|
||||||
|
module = self.readline()[:-1]
|
||||||
|
name = self.readline()[:-1]
|
||||||
|
klass = self.find_class(module, name)
|
||||||
|
self.stack.append(klass)
|
||||||
|
return klass
|
||||||
|
dispatch[CLASS] = load_class
|
||||||
|
|
||||||
|
def find_class(self, module, name):
|
||||||
env = {}
|
env = {}
|
||||||
try:
|
try:
|
||||||
exec 'from %s import %s' % (module, name) in env
|
exec 'from %s import %s' % (module, name) in env
|
||||||
|
@ -417,15 +443,12 @@ class Unpickler:
|
||||||
raise SystemError, \
|
raise SystemError, \
|
||||||
"Failed to import class %s from module %s" % \
|
"Failed to import class %s from module %s" % \
|
||||||
(name, module)
|
(name, module)
|
||||||
else:
|
|
||||||
klass = env[name]
|
klass = env[name]
|
||||||
if type(klass) != ClassType:
|
if type(klass) != ClassType:
|
||||||
raise SystemError, \
|
raise SystemError, \
|
||||||
"imported object %s from module %s is not a class" % \
|
"Imported object %s from module %s is not a class" % \
|
||||||
(name, module)
|
(name, module)
|
||||||
value = apply(klass, args)
|
return klass
|
||||||
self.stack.append(value)
|
|
||||||
dispatch[INST] = load_inst
|
|
||||||
|
|
||||||
def load_pop(self):
|
def load_pop(self):
|
||||||
del self.stack[-1]
|
del self.stack[-1]
|
||||||
|
@ -482,6 +505,28 @@ class Unpickler:
|
||||||
dispatch[STOP] = load_stop
|
dispatch[STOP] = load_stop
|
||||||
|
|
||||||
|
|
||||||
|
# Shorthands
|
||||||
|
|
||||||
|
def dump(object, file):
|
||||||
|
Pickler(file).dump(object)
|
||||||
|
|
||||||
|
def dumps(object):
|
||||||
|
import StringIO
|
||||||
|
file = StringIO.StringIO()
|
||||||
|
Pickler(file).dump(object)
|
||||||
|
return file.getvalue()
|
||||||
|
|
||||||
|
def load(file):
|
||||||
|
return Unpickler(file).load()
|
||||||
|
|
||||||
|
def loads(str):
|
||||||
|
import StringIO
|
||||||
|
file = StringIO.StringIO(str)
|
||||||
|
return Unpickler(file).load()
|
||||||
|
|
||||||
|
|
||||||
|
# The rest is used for testing only
|
||||||
|
|
||||||
class C:
|
class C:
|
||||||
def __cmp__(self, other):
|
def __cmp__(self, other):
|
||||||
return cmp(self.__dict__, other.__dict__)
|
return cmp(self.__dict__, other.__dict__)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue