From 585063f6e18a37e90febc4409595f99f8d35c3f8 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Fri, 9 Mar 2001 20:04:56 +0000 Subject: [PATCH] Small enhancements. [SVN r9532] --- doc/pickle.html | 136 +++++++++++++++++++++++++++--------------------- 1 file changed, 77 insertions(+), 59 deletions(-) diff --git a/doc/pickle.html b/doc/pickle.html index 3ec8c928..39cb07dc 100644 --- a/doc/pickle.html +++ b/doc/pickle.html @@ -45,81 +45,87 @@ methods:
-__getinitargs__ +__getinitargs__
- When an instance of a Boost.Python extension class is pickled, the pickler - tests if the instance has a __getinitargs__ method. This method must - return a Python tuple. When the instance is restored by the + When an instance of a Boost.Python extension class is pickled, the + pickler tests if the instance has a __getinitargs__ method. + This method must return a Python tuple (it is most convenient to use + a boost::python::tuple). When the instance is restored by the unpickler, the contents of this tuple are used as the arguments for the class constructor.

- If __getinitargs__ is not defined, the class constructor will be - called without arguments. + If __getinitargs__ is not defined, the class constructor + will be called without arguments.

-__getstate__ +__getstate__
- When an instance of a Boost.Python extension class is pickled, the pickler - tests if the instance has a __getstate__ method. This method should - return a Python object representing the state of the instance. + When an instance of a Boost.Python extension class is pickled, the + pickler tests if the instance has a __getstate__ method. + This method should return a Python object representing the state of + the instance.

- If __getstate__ is not defined, the instance's __dict__ is pickled - (if it is not empty). + If __getstate__ is not defined, the instance's + __dict__ is pickled (if it is not empty).

-__setstate__ +__setstate__
When an instance of a Boost.Python extension class is restored by the unpickler, it is first constructed using the result of - __getinitargs__ as arguments (see above). Subsequently the unpickler - tests if the new instance has a __setstate__ method. If so, this - method is called with the result of __getstate__ (a Python object) as - the argument. + __getinitargs__ as arguments (see above). Subsequently the + unpickler tests if the new instance has a __setstate__ + method. If so, this method is called with the result of + __getstate__ (a Python object) as the argument.

- If __setstate__ is not defined, the result of __getstate__ must be - a Python dictionary. The items of this dictionary are added to - the instance's __dict__. + If __setstate__ is not defined, the result of + __getstate__ must be a Python dictionary. The items of this + dictionary are added to the instance's __dict__. +

-If both __getstate__ and __setstate__ are defined, the Python object -returned by __getstate__ need not be a dictionary. The __getstate__ and -__setstate__ methods can do what they want. +If both __getstate__ and __setstate__ are defined, +the Python object returned by __getstate__ need not be a +dictionary. The __getstate__ and __setstate__ methods +can do what they want.

Pitfalls and Safety Guards

-In Boost.Python extension modules with many extension classes, providing -complete pickle support for all classes would be a significant -overhead. In general complete pickle support should only be implemented -for extension classes that will eventually be pickled. However, the -author of a Boost.Python extension module might not anticipate correctly which -classes need support for pickle. Unfortunately, the pickle protocol -described above has two important pitfalls that the end user of a Boost.Python -extension module might not be aware of: +In Boost.Python extension modules with many extension classes, +providing complete pickle support for all classes would be a +significant overhead. In general complete pickle support should only be +implemented for extension classes that will eventually be pickled. +However, the author of a Boost.Python extension module might not +anticipate correctly which classes need support for pickle. +Unfortunately, the pickle protocol described above has two important +pitfalls that the end user of a Boost.Python extension module might not +be aware of:
Pitfall 1: -Both __getinitargs__ and __getstate__ are not defined. +Both __getinitargs__ and __getstate__ are not defined.
In this situation the unpickler calls the class constructor without - arguments and then adds the __dict__ that was pickled by default to - that of the new instance. + arguments and then adds the __dict__ that was pickled by + default to that of the new instance.

- However, most C++ classes wrapped with Boost.Python will have member data - that are not restored correctly by this procedure. To alert the user - to this problem, a safety guard is provided. If both __getinitargs__ - and __getstate__ are not defined, Boost.Python tests if the class has an - attribute __dict_defines_state__. An exception is raised if this + However, most C++ classes wrapped with Boost.Python will have member + data that are not restored correctly by this procedure. To alert the + user to this problem, a safety guard is provided. If both + __getinitargs__ and __getstate__ are not defined, + Boost.Python tests if the class has an attribute + __dict_defines_state__. An exception is raised if this attribute is not defined:

@@ -147,41 +153,44 @@ Both __getinitargs__ and __getstate__ are not defined.
 

Pitfall 2: -__getstate__ is defined and the instance's __dict__ is not empty. +__getstate__ is defined and the instance's __dict__ is not empty.
- The author of a Boost.Python extension class might provide a __getstate__ - method without considering the possibilities that: + The author of a Boost.Python extension class might provide a + __getstate__ method without considering the possibilities + that:

  • - his class is used as a base class. Most likely the __dict__ of - instances of the derived class needs to be pickled in order to - restore the instances correctly. + his class is used in Python as a base class. Most likely the + __dict__ of instances of the derived class needs to be + pickled in order to restore the instances correctly.

  • - the user adds items to the instance's __dict__ directly. Again, - the __dict__ of the instance then needs to be pickled. + the user adds items to the instance's __dict__ directly. + Again, the __dict__ of the instance then needs to be + pickled. +

To alert the user to this highly unobvious problem, a safety guard is - provided. If __getstate__ is defined and the instance's __dict__ is - not empty, Boost.Python tests if the class has an attribute - __getstate_manages_dict__. An exception is raised if this attribute - is not defined: + provided. If __getstate__ is defined and the instance's + __dict__ is not empty, Boost.Python tests if the class has + an attribute __getstate_manages_dict__. An exception is + raised if this attribute is not defined:

     RuntimeError: Incomplete pickle support (__getstate_manages_dict__ not set)
 
To resolve this problem, it should first be established that the - __getstate__ and __setstate__ methods manage the instances's __dict__ - correctly. Note that this can be done both at the C++ and the Python - level. Finally, the safety guard should intentionally be overridden. - E.g. in C++: + __getstate__ and __setstate__ methods manage the + instances's __dict__ correctly. Note that this can be done + both at the C++ and the Python level. Finally, the safety guard + should intentionally be overridden. E.g. in C++:
     class_builder<your_class> py_your_class(your_module, "your_class");
@@ -206,15 +215,24 @@ __getstate__ is defined and the instance's __dict__ is not empty.
 
 
  • - Avoid using __getstate__ if the instance can also be reconstructed - by way of __getinitargs__. This automatically avoids Pitfall 2. + Avoid using __getstate__ if the instance can also be + reconstructed by way of __getinitargs__. This automatically + avoids Pitfall 2.

  • - If __getstate__ is required, include the instance's __dict__ in the - Python object that is returned. + If __getstate__ is required, include the instance's + __dict__ in the Python object that is returned. +
+
+

Example

+ +An example that shows how to provide pickle support is available in the +boost/lib/python/example directory +(getting_started3.cpp). +
Author: Ralf W. Grosse-Kunstleve, March 2001