diff options
author | Guido van Rossum <guido@python.org> | 2003-01-31 16:51:45 (GMT) |
---|---|---|
committer | Guido van Rossum <guido@python.org> | 2003-01-31 16:51:45 (GMT) |
commit | d053b4b41663b3ebf5795790e390e1dab96f2d58 (patch) | |
tree | 8cfe9e57f99c761560e0f4e5c178c5abe7bd6a35 /Lib/pickle.py | |
parent | 4b23f2b44bdd13758eab6808d6a08b951fbfc4dd (diff) | |
download | cpython-d053b4b41663b3ebf5795790e390e1dab96f2d58.zip cpython-d053b4b41663b3ebf5795790e390e1dab96f2d58.tar.gz cpython-d053b4b41663b3ebf5795790e390e1dab96f2d58.tar.bz2 |
Add a magical feature to save_reduce so that __reduce__ can cause
NEWOBJ to be generated.
Diffstat (limited to 'Lib/pickle.py')
-rw-r--r-- | Lib/pickle.py | 44 |
1 files changed, 40 insertions, 4 deletions
diff --git a/Lib/pickle.py b/Lib/pickle.py index 5106ec9..bb840c9 100644 --- a/Lib/pickle.py +++ b/Lib/pickle.py @@ -365,9 +365,46 @@ class Pickler: save = self.save write = self.write - save(func) - save(args) - write(REDUCE) + # Protocol 2 special case: if func's name is __newobj__, use NEWOBJ + if self.proto >= 2 and getattr(func, "__name__", "") == "__newobj__": + # A __reduce__ implementation can direct protocol 2 to + # use the more efficient NEWOBJ opcode, while still + # allowing protocol 0 and 1 to work normally. For this to + # work, the function returned by __reduce__ should be + # called __newobj__, and its first argument should be a + # new-style class. The implementation for __newobj__ + # should be as follows, although pickle has no way to + # verify this: + # + # def __newobj__(cls, *args): + # return cls.__new__(cls, *args) + # + # Protocols 0 and 1 will pickle a reference to __newobj__, + # while protocol 2 (and above) will pickle a reference to + # cls, the remaining args tuple, and the NEWOBJ code, + # which calls cls.__new__(cls, *args) at unpickling time + # (see load_newobj below). If __reduce__ returns a + # three-tuple, the state from the third tuple item will be + # pickled regardless of the protocol, calling __setstate__ + # at unpickling time (see load_build below). + # + # Note that no standard __newobj__ implementation exists; + # you have to provide your own. This is to enforce + # compatibility with Python 2.2 (pickles written using + # protocol 0 or 1 in Python 2.3 should be unpicklable by + # Python 2.2). + cls = args[0] + if not hasattr(cls, "__new__"): + raise PicklingError( + "args[0] from __newobj__ args has no __new__") + args = args[1:] + save(cls) + save(args) + write(NEWOBJ) + else: + save(func) + save(args) + write(REDUCE) if state is not None: save(state) @@ -375,7 +412,6 @@ class Pickler: def save_newobj(self, obj): # Save a new-style class instance, using protocol 2. - # XXX This is still experimental. assert self.proto >= 2 # This only works for protocol 2 t = type(obj) getnewargs = getattr(obj, "__getnewargs__", None) |