2
0
mirror of https://github.com/boostorg/python.git synced 2026-01-27 19:12:16 +00:00

Small enhancements.

[SVN r9532]
This commit is contained in:
Ralf W. Grosse-Kunstleve
2001-03-09 20:04:56 +00:00
parent 494f12090f
commit 585063f6e1

View File

@@ -45,81 +45,87 @@ methods:
<dl>
<dt>
<strong>__getinitargs__</strong>
<strong><tt>__getinitargs__</tt></strong>
<dd>
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 <tt>__getinitargs__</tt> 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.
<p>
If __getinitargs__ is not defined, the class constructor will be
called without arguments.
If <tt>__getinitargs__</tt> is not defined, the class constructor
will be called without arguments.
<p>
<dt>
<strong>__getstate__</strong>
<strong><tt>__getstate__</tt></strong>
<dd>
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 <tt>__getstate__</tt> method.
This method should return a Python object representing the state of
the instance.
<p>
If __getstate__ is not defined, the instance's __dict__ is pickled
(if it is not empty).
If <tt>__getstate__</tt> is not defined, the instance's
<tt>__dict__</tt> is pickled (if it is not empty).
<p>
<dt>
<strong>__setstate__</strong>
<strong><tt>__setstate__</tt></strong>
<dd>
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.
<tt>__getinitargs__</tt> as arguments (see above). Subsequently the
unpickler tests if the new instance has a <tt>__setstate__</tt>
method. If so, this method is called with the result of
<tt>__getstate__</tt> (a Python object) as the argument.
<p>
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 <tt>__setstate__</tt> is not defined, the result of
<tt>__getstate__</tt> must be a Python dictionary. The items of this
dictionary are added to the instance's <tt>__dict__</tt>.
</dl>
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 <tt>__getstate__</tt> and <tt>__setstate__</tt> are defined,
the Python object returned by <tt>__getstate__</tt> need not be a
dictionary. The <tt>__getstate__</tt> and <tt>__setstate__</tt> methods
can do what they want.
<hr>
<h2>Pitfalls and Safety Guards</h2>
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:
<dl>
<dt>
<strong>Pitfall 1:</strong>
Both __getinitargs__ and __getstate__ are not defined.
Both <tt>__getinitargs__</tt> and <tt>__getstate__</tt> are not defined.
<dd>
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 <tt>__dict__</tt> that was pickled by
default to that of the new instance.
<p>
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
<tt>__getinitargs__</tt> and <tt>__getstate__</tt> are not defined,
Boost.Python tests if the class has an attribute
<tt>__dict_defines_state__</tt>. An exception is raised if this
attribute is not defined:
<pre>
@@ -147,41 +153,44 @@ Both __getinitargs__ and __getstate__ are not defined.
<p>
<dt>
<strong>Pitfall 2:</strong>
__getstate__ is defined and the instance's __dict__ is not empty.
<tt>__getstate__</tt> is defined and the instance's <tt>__dict__</tt> is not empty.
<dd>
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
<tt>__getstate__</tt> method without considering the possibilities
that:
<p>
<ul>
<li>
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
<tt>__dict__</tt> of instances of the derived class needs to be
pickled in order to restore the instances correctly.
<p>
<li>
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 <tt>__dict__</tt> directly.
Again, the <tt>__dict__</tt> of the instance then needs to be
pickled.
</ul>
<p>
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 <tt>__getstate__</tt> is defined and the instance's
<tt>__dict__</tt> is not empty, Boost.Python tests if the class has
an attribute <tt>__getstate_manages_dict__</tt>. An exception is
raised if this attribute is not defined:
<pre>
RuntimeError: Incomplete pickle support (__getstate_manages_dict__ not set)
</pre>
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++:
<tt>__getstate__</tt> and <tt>__setstate__</tt> methods manage the
instances's <tt>__dict__</tt> 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++:
<pre>
class_builder&lt;your_class&gt; py_your_class(your_module, "your_class");
@@ -206,15 +215,24 @@ __getstate__ is defined and the instance's __dict__ is not empty.
<ul>
<li>
Avoid using __getstate__ if the instance can also be reconstructed
by way of __getinitargs__. This automatically avoids Pitfall 2.
Avoid using <tt>__getstate__</tt> if the instance can also be
reconstructed by way of <tt>__getinitargs__</tt>. This automatically
avoids Pitfall 2.
<p>
<li>
If __getstate__ is required, include the instance's __dict__ in the
Python object that is returned.
If <tt>__getstate__</tt> is required, include the instance's
<tt>__dict__</tt> in the Python object that is returned.
</ul>
<hr>
<h2>Example</h2>
An example that shows how to provide pickle support is available in the
<tt>boost/lib/python/example</tt> directory
(<tt>getting_started3.cpp</tt>).
<hr>
<address>
Author: Ralf W. Grosse-Kunstleve, March 2001