mirror of https://github.com/python/cpython.git
pickle classes; add format_version, load(s)/dump(s) shortcuts
This commit is contained in:
parent
cc08112ff4
commit
0c891ce61a
|
@ -17,7 +17,7 @@
|
|||
|
||||
- recursive objects
|
||||
- pointer sharing
|
||||
- class instances
|
||||
- classes and class instances
|
||||
|
||||
Pickle is Python-specific. This has the advantage that there are no
|
||||
restrictions imposed by external standards such as CORBA (which probably
|
||||
|
@ -62,7 +62,7 @@
|
|||
return a *tuple* containing the arguments to be passed to the class
|
||||
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
|
||||
as the contents for the instance, and if the class defines the
|
||||
method __setstate__, it is called with the unpickled state. (Note
|
||||
|
@ -108,6 +108,7 @@
|
|||
- strings
|
||||
- tuples, lists and dictionaries containing only picklable objects
|
||||
- class instances whose __dict__ or __setstate__() is picklable
|
||||
- classes
|
||||
|
||||
Attempts to pickle unpicklable objects will raise an exception
|
||||
after having written an unspecified number of bytes to the file argument.
|
||||
|
@ -125,12 +126,14 @@
|
|||
I have no answers. Garbage Collection may also become a problem here.)
|
||||
"""
|
||||
|
||||
__format_version__ = "1.0" # File format version
|
||||
__version__ = "1.4" # Code version
|
||||
__version__ = "1.5" # Code version
|
||||
|
||||
from types import *
|
||||
import string
|
||||
|
||||
format_version = "1.1" # File format version we write
|
||||
compatible_formats = ["1.0"] # Old format versions we can read
|
||||
|
||||
PicklingError = "pickle.PicklingError"
|
||||
|
||||
AtomicTypes = [NoneType, IntType, FloatType, StringType]
|
||||
|
@ -153,6 +156,7 @@ def safe(object):
|
|||
LIST = 'l'
|
||||
DICT = 'd'
|
||||
INST = 'i'
|
||||
CLASS = 'c'
|
||||
GET = 'g'
|
||||
PUT = 'p'
|
||||
APPEND = 'a'
|
||||
|
@ -300,8 +304,8 @@ def save_inst(self, object):
|
|||
self.write(MARK)
|
||||
for arg in args:
|
||||
self.save(arg)
|
||||
self.write(INST + module + '\n' + name + '\n' +
|
||||
PUT + `d` + '\n')
|
||||
self.write(INST + module + '\n' + name + '\n' +
|
||||
PUT + `d` + '\n')
|
||||
self.memo[d] = object
|
||||
try:
|
||||
getstate = object.__getstate__
|
||||
|
@ -313,6 +317,14 @@ def save_inst(self, object):
|
|||
self.write(BUILD)
|
||||
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 = {}
|
||||
|
||||
|
@ -410,6 +422,20 @@ def load_inst(self):
|
|||
del self.stack[k:]
|
||||
module = 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 = {}
|
||||
try:
|
||||
exec 'from %s import %s' % (module, name) in env
|
||||
|
@ -417,18 +443,15 @@ def load_inst(self):
|
|||
raise SystemError, \
|
||||
"Failed to import class %s from module %s" % \
|
||||
(name, module)
|
||||
else:
|
||||
klass = env[name]
|
||||
if type(klass) != ClassType:
|
||||
raise SystemError, \
|
||||
"imported object %s from module %s is not a class" % \
|
||||
(name, module)
|
||||
value = apply(klass, args)
|
||||
self.stack.append(value)
|
||||
dispatch[INST] = load_inst
|
||||
klass = env[name]
|
||||
if type(klass) != ClassType:
|
||||
raise SystemError, \
|
||||
"Imported object %s from module %s is not a class" % \
|
||||
(name, module)
|
||||
return klass
|
||||
|
||||
def load_pop(self):
|
||||
del self.stack[-1]
|
||||
del self.stack[-1]
|
||||
dispatch[POP] = load_pop
|
||||
|
||||
def load_dup(self):
|
||||
|
@ -482,6 +505,28 @@ def load_stop(self):
|
|||
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:
|
||||
def __cmp__(self, other):
|
||||
return cmp(self.__dict__, other.__dict__)
|
||||
|
|
Loading…
Reference in New Issue