[Python-checkins] python/nondist/peps pep-0307.txt,1.6,1.7

gvanrossum@users.sourceforge.net gvanrossum@users.sourceforge.net
Mon, 03 Feb 2003 12:22:26 -0800


Update of /cvsroot/python/python/nondist/peps
In directory sc8-pr-cvs1:/tmp/cvs-serv17587

Modified Files:
	pep-0307.txt 
Log Message:
Added docs for __getstate__ and __setstate__, __getinitargs__ and
__getnewargs__.  Unfortunately these need to be refactored again
according to a different organizing principle. ;-(


Index: pep-0307.txt
===================================================================
RCS file: /cvsroot/python/python/nondist/peps/pep-0307.txt,v
retrieving revision 1.6
retrieving revision 1.7
diff -C2 -d -r1.6 -r1.7
*** pep-0307.txt	3 Feb 2003 17:50:16 -0000	1.6
--- pep-0307.txt	3 Feb 2003 20:22:23 -0000	1.7
***************
*** 138,141 ****
--- 138,145 ----
      though, and we'll refer to these collectively as __reduce__.
  
+     IMPORTANT: a classic class cannot provide __reduce__
+     functionality.  It must use __getinitargs__ and/or __gestate__ to
+     customize pickling.  These are described below.
+ 
      __reduce__ must return either a string or a tuple.  If it returns
      a string, this is an object whose state is not to be pickled, but
***************
*** 213,216 ****
--- 217,232 ----
  
  
+ XXX Refactoring needed
+ 
+     The following sections should really be reorganized according to
+     the following cases:
+ 
+     1. classic classes, all protocols
+ 
+     2. new-style classes, protocols 0 and 1
+ 
+     3. new-style classes, protocol 2
+ 
+ 
  The __newobj__ unpickling function
  
***************
*** 236,239 ****
--- 252,395 ----
      in the recommended implementation of __newobj__ that depends on
      Python 2.3.
+ 
+ 
+ The __getstate__ and __setstate__ methods
+ 
+     When there is no __reduce__ for an object, the primary ways to
+     customize pickling is by specifying __getstate__ and/or
+     __setstate__ methods.  These are supported for classic classes as
+     well as for new-style classes for which no __reduce__ exists.
+ 
+     When __reduce__ exists, __getstate__ is not called (unless your
+     __reduce__ implementation calls it), but __getstate__ will be
+     called with the third item from the tuple returned by __reduce__,
+     if not None.
+ 
+     There's a subtle difference between classic and new-style classes
+     here: if a classic class's __getstate__ returns None,
+     self.__setstate__(None) will be called as part of unpickling.  But
+     if a new-style class's __getstate__ returns None, its __setstate__
+     won't be called at all as part of unpickling.
+ 
+     The __getstate__ method is supposed to return a picklable version
+     of an object's state that does not reference the object itself.
+     If no __getstate__ method exists, a default state is assumed.
+     There are several cases:
+ 
+     - For a classic class, the default state is self.__dict__.
+ 
+     - For a new-style class that has an instance __dict__ and no
+       __slots__, the default state is self.__dict__.
+ 
+     - For a new-style class that has no instance __dict__ and no
+       __slots__, the default __state__ is None.
+ 
+     - For a new-style class that has an instance __dict__ and
+       __slots__, the default state is a tuple consisting of two
+       dictionaries: the first being self.__dict__, and the second
+       being a dictionary mapping slot names to slot values.  Only
+       slots that have a value are included in the latter.
+ 
+     - For a new-style class that has __slots__ and no instance
+       __dict__, the default state is a tuple whose first item is None
+       and whose second item is a dictionary mapping slot names to slot
+       values described in the previous bullet.
+ 
+     The __setstate__ should take one argument; it will be called with
+     the value returned by __getstate__ or with the default state
+     described above if no __setstate__ method is defined.
+ 
+     If no __setstate__ method exists, a default implementation is
+     provided that can handle the state returned by the default
+     __getstate__.
+ 
+     It is fine if a class implements one of these but not the other,
+     as long as it is compatible with the default version.
+ 
+     New-style classes that inherit a default __reduce__ implementation
+     from the ultimate base class 'object'.  This implementation is not
+     used for protocol 2, and then last four bullets above apply.  For
+     protocols 0 and 1, the default implementation looks for a
+     __getstate__ method, and if none exists, it uses a simpler default
+     strategy:
+ 
+     - If there is an instance __dict__, the state is self.__dict__.
+ 
+     - Otherwise, the state is None (and __setstate__ will not be
+       called).
+ 
+     Note that this strategy ignores slots.  New-style classes that
+     define slots and don't define __getstate__ in the same class that
+     defines the slots automatically have a __getstate__ method added
+     that raises TypeError.  Protocol 2 ignores this __getstate__
+     method (recognized by the specific text of the error message).
+ 
+ 
+ The __getinitargs__ and __getnewargs__ methods
+ 
+     The __setstate__ method (or its default implementation) requires
+     that a new object already exists so that its __setstate__ method
+     can be called.  The point is to create a new object that isn't
+     fully initialized; in particular, the class's __init__ method
+     should not be called if possible.
+ 
+     The way this is done differs between classic and new-style
+     classes.
+ 
+     For classic classes, these are the possibilities:
+ 
+     - Normally, the following trick is used: create an instance of a
+       trivial classic class (one without any methods or instance
+       variables) and then use __class__ assignment to change its class
+       to the desired class.  This creates an instance of the desired
+       class with an empty __dict__ whose __init__ has not been called.
+ 
+     - However, if the class has a method named __getinitargs__, the
+       above trick is not used, and a class instance is created by
+       using the tuple returned by __getinitargs__ as an argument list
+       to the class constructor.  This is done even if __getinitargs__
+       returns an empty tuple -- a __getinitargs__ method that returns
+       () is not equivalent to not having __getinitargs__ at all.
+       __getinitargs__ *must* return a tuple.
+ 
+     - In restricted execution mode, the trick from the first bullet
+       doesn't work; in this case, the class constructor is called with
+       an empty argument list if no __getinitargs__ method exists.
+       This means that in order for a classic class to be unpicklable
+       in restricted mode, it must either implement __getinitargs__ or
+       its constructor (i.e., its __init__ method) must be callable
+       without arguments.
+ 
+     For new-style classes, these are the possibilities:
+ 
+     - When using protocol 0 or 1, a default __reduce__ implementation
+       is normally inherited from the ultimate base class class
+       'object'.  This implementation finds the nearest base class that
+       is implemented in C (either as a built-in type or as a type
+       defined by an extension class).  Calling this base class B and
+       the class of the object to be pickled C, the new object is
+       created at unpickling time using the following code:
+ 
+          obj = B.__new__(C, state)
+          B.__init__(obj, state)
+ 
+       where state is a value computed at pickling time as follows:
+ 
+         state = B(obj)
+ 
+       This only works when B is not C, and only for certain classes
+       B.  It does work for the following built-in classes: int, long,
+       float, complex, str, unicode, tuple, list, dict; and this is its
+       main redeeming factor.
+ 
+     - When using protocol 2, the default __reduce__ implementation
+       inherited from 'object' is ignored.  Instead, a new pickling
+       opcode is generated that causes a new object to be created as
+       follows:
+ 
+         obj = C.__new__(C, *args)
+ 
+       where args is either the empty tuple, or the tuple returned by
+       the __getnewargs__ method, if defined.