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:
136
doc/pickle.html
136
doc/pickle.html
@@ -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<your_class> 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
|
||||
|
||||
Reference in New Issue
Block a user