tests and docs for stl_input_iterator

[SVN r31514]
This commit is contained in:
Eric Niebler 2005-10-31 18:50:18 +00:00
parent 6ec4387ea1
commit 6fee43fc6f
20 changed files with 2458 additions and 1431 deletions

View File

@ -51,6 +51,7 @@ if [ check-python-config ]
converter/builtin_converters.cpp
converter/arg_to_python_base.cpp
object/iterator.cpp
object/stl_iterator.cpp
object_protocol.cpp
object_operators.cpp
wrapper.cpp

View File

@ -50,6 +50,7 @@ lib boost_python
converter/builtin_converters.cpp
converter/arg_to_python_base.cpp
object/iterator.cpp
object/stl_iterator.cpp
object_protocol.cpp
object_operators.cpp
wrapper.cpp

View File

@ -179,6 +179,10 @@ SOURCE=..\..\src\slice.cpp
# End Source File
# Begin Source File
SOURCE=..\..\src\object\stl_iterator.cpp
# End Source File
# Begin Source File
SOURCE=..\..\src\str.cpp
# End Source File
# Begin Source File
@ -602,6 +606,10 @@ SOURCE=..\..\..\..\boost\python\object\select_holder.hpp
# End Source File
# Begin Source File
SOURCE=..\..\..\..\boost\python\object\stl_iterator_core.hpp
# End Source File
# Begin Source File
SOURCE=..\..\..\..\boost\python\object\value_holder.hpp
# End Source File
# Begin Source File
@ -859,6 +867,10 @@ SOURCE=..\..\..\..\boost\python\slice_nil.hpp
# End Source File
# Begin Source File
SOURCE=..\..\..\..\boost\python\stl_iterator.hpp
# End Source File
# Begin Source File
SOURCE=..\..\..\..\boost\python\str.hpp
# End Source File
# Begin Source File

View File

@ -28,15 +28,13 @@
<div><div class="author"><h3 class="author">
<span class="firstname">David</span> <span class="surname">Abrahams</span>
</h3></div></div>
<div><p class="copyright">Copyright © 2002-2005 Joel de Guzman, David Abrahams</p></div>
<div><p class="copyright">Copyright © 2002-2005 Joel
de Guzman, David Abrahams</p></div>
<div><div class="legalnotice">
<a name="id442427"></a><p>
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
<a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">
http://www.boost.org/LICENSE_1_0.txt
</a>)
<a name="id427816"></a><p>
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">
http://www.boost.org/LICENSE_1_0.txt </a>)
</p>
</div></div>
</div></div>
@ -85,47 +83,59 @@
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="python.quickstart"></a>QuickStart</h2></div></div></div>
<p>
The Boost Python Library is a framework for interfacing Python and
C++. It allows you to quickly and seamlessly expose C++ classes
functions and objects to Python, and vice-versa, using no special
tools -- just your C++ compiler. It is designed to wrap C++ interfaces
non-intrusively, so that you should not have to change the C++ code at
all in order to wrap it, making Boost.Python ideal for exposing
3rd-party libraries to Python. The library's use of advanced
metaprogramming techniques simplifies its syntax for users, so that
wrapping code takes on the look of a kind of declarative interface
definition language (IDL).</p>
QuickStartThe Boost Python Library is a framework for interfacing Python and
C++. It allows you to quickly and seamlessly expose C++ classes functions and
objects to Python, and vice-versa, using no special tools -- just your C++
compiler. It is designed to wrap C++ interfaces non-intrusively, so that you
should not have to change the C++ code at all in order to wrap it, making Boost.Python
ideal for exposing 3rd-party libraries to Python. The library's use of advanced
metaprogramming techniques simplifies its syntax for users, so that wrapping
code takes on the look of a kind of declarative interface definition language
(IDL).
</p>
<a name="quickstart.hello_world"></a><h2>
<a name="id372086"></a>Hello World</h2>
<a name="id372244"></a>
Hello World
</h2>
<p>
Following C/C++ tradition, let's start with the "hello, world". A C++
Function:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">char</span><span class="keyword"> const</span><span class="special">*</span><span class="identifier"> greet</span><span class="special">()</span><span class="special">
{</span><span class="keyword">
return</span><span class="string"> "hello, world"</span><span class="special">;</span><span class="special">
}</span></tt></pre>
Following C/C++ tradition, let's start with the "hello, world". A
C++ Function:
</p>
<pre class="programlisting">
<span class="keyword">char</span> <span class="keyword">const</span><span class="special">*</span> <span class="identifier">greet</span><span class="special">()</span>
<span class="special">{</span>
<span class="keyword">return</span> <span class="string">"hello, world"</span><span class="special">;</span>
<span class="special">}</span>
</pre>
<p>
can be exposed to Python by writing a Boost.Python wrapper:</p>
<pre class="programlisting"><tt class="literal"><span class="preprocessor">#include</span><span class="special"> &lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">python</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span><span class="keyword">
using</span><span class="keyword"> namespace</span><span class="identifier"> boost</span><span class="special">::</span><span class="identifier">python</span><span class="special">;</span><span class="identifier">
can be exposed to Python by writing a Boost.Python wrapper:
</p>
<pre class="programlisting">
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">python</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="keyword">using</span> <span class="keyword">namespace</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">python</span><span class="special">;</span>
BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">hello</span><span class="special">)</span><span class="special">
{</span><span class="identifier">
def</span><span class="special">(</span><span class="string">"greet"</span><span class="special">,</span><span class="identifier"> greet</span><span class="special">);</span><span class="special">
}</span></tt></pre>
<span class="identifier">BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">hello</span><span class="special">)</span>
<span class="special">{</span>
<span class="identifier">def</span><span class="special">(</span><span class="string">"greet"</span><span class="special">,</span> <span class="identifier">greet</span><span class="special">);</span>
<span class="special">}</span>
</pre>
<p>
That's it. We're done. We can now build this as a shared library. The
resulting DLL is now visible to Python. Here's a sample Python session:</p>
That's it. We're done. We can now build this as a shared library. The resulting
DLL is now visible to Python. Here's a sample Python session:
</p>
<p></p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="keyword"> import</span><span class="identifier"> hello</span><span class="special">
&gt;&gt;&gt;</span><span class="keyword"> print</span><span class="identifier"> hello</span><span class="special">.</span><span class="identifier">greet</span><span class="special">()</span><span class="identifier">
hello</span><span class="special">,</span><span class="identifier"> world</span></tt></pre>
<pre class="programlisting">
<span class="special">&gt;&gt;&gt;</span> <span class="keyword">import</span> <span class="identifier">hello</span>
<span class="special">&gt;&gt;&gt;</span> <span class="keyword">print</span> <span class="identifier">hello</span><span class="special">.</span><span class="identifier">greet</span><span class="special">()</span>
<span class="identifier">hello</span><span class="special">,</span> <span class="identifier">world</span>
</pre>
<p></p>
<div class="blockquote"><blockquote class="blockquote"><p><span class="emphasis"><em><span class="bold"><b>Next stop... Building your Hello World module from start to finish...</b></span></em></span></p></blockquote></div>
<div class="blockquote"><blockquote class="blockquote"><p><span class="emphasis"><em><span class="bold"><b>Next stop... Building your Hello World module
from start to finish...</b></span></em></span></p></blockquote></div>
</div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"><small><p>Last revised: July 12, 2005 at 07:50:43 GMT</p></small></td>
<td align="left"><small><p>Last revised: October 31, 2005 at 18:46:06 GMT</p></small></td>
<td align="right"><small></small></td>
</tr></table>
<hr>

View File

@ -27,39 +27,47 @@
<a name="python.embedding"></a>Embedding</h2></div></div></div>
<div class="toc"><dl><dt><span class="section"><a href="embedding.html#python.using_the_interpreter">Using the interpreter</a></span></dt></dl></div>
<p>
By now you should know how to use Boost.Python to call your C++ code from
Python. However, sometimes you may need to do the reverse: call Python code
from the C++-side. This requires you to <span class="emphasis"><em>embed</em></span> the Python interpreter
into your C++ program.</p>
EmbeddingBy now you should know how to use Boost.Python to call your C++ code
from Python. However, sometimes you may need to do the reverse: call Python
code from the C++-side. This requires you to <span class="emphasis"><em>embed</em></span> the
Python interpreter into your C++ program.
</p>
<p>
Currently, Boost.Python does not directly support everything you'll need
when embedding. Therefore you'll need to use the
<a href="http://www.python.org/doc/current/api/api.html" target="_top">Python/C API</a> to fill in
the gaps. However, Boost.Python already makes embedding a lot easier and,
in a future version, it may become unnecessary to touch the Python/C API at
all. So stay tuned... <span class="inlinemediaobject"><img src="../images/smiley.png"></span></p>
Currently, Boost.Python does not directly support everything you'll need when
embedding. Therefore you'll need to use the <a href="http://www.python.org/doc/current/api/api.html" target="_top">Python/C
API</a> to fill in the gaps. However, Boost.Python already makes embedding
a lot easier and, in a future version, it may become unnecessary to touch the
Python/C API at all. So stay tuned... <span class="inlinemediaobject"><img src="../images/smiley.png"></span></p>
<a name="embedding.building_embedded_programs"></a><h2>
<a name="id456196"></a>Building embedded programs</h2>
<a name="id457321"></a>
Building embedded programs
</h2>
<p>
To be able to use embedding in your programs, they have to be linked to
both Boost.Python's and Python's static link library.</p>
To be able to use embedding in your programs, they have to be linked to both
Boost.Python's and Python's static link library.
</p>
<p>
Boost.Python's static link library comes in two variants. Both are located
in Boost's <tt class="literal">/libs/python/build/bin-stage</tt> subdirectory. On Windows, the
variants are called <tt class="literal">boost_python.lib</tt> (for release builds) and
<tt class="literal">boost_python_debug.lib</tt> (for debugging). If you can't find the libraries,
you probably haven't built Boost.Python yet. See
<a href="../../../../building.html" target="_top">Building and Testing</a> on how to do this.</p>
Boost.Python's static link library comes in two variants. Both are located
in Boost's <tt class="literal">/libs/python/build/bin-stage</tt> subdirectory. On
Windows, the variants are called <tt class="literal">boost_python.lib</tt> (for release
builds) and <tt class="literal">boost_python_debug.lib</tt> (for debugging). If you
can't find the libraries, you probably haven't built Boost.Python yet. See
<a href="../../../../building.html" target="_top">Building and Testing</a> on how to
do this.
</p>
<p>
Python's static link library can be found in the <tt class="literal">/libs</tt> subdirectory of
your Python directory. On Windows it is called pythonXY.lib where X.Y is
your major Python version number.</p>
Python's static link library can be found in the <tt class="literal">/libs</tt> subdirectory
of your Python directory. On Windows it is called pythonXY.lib where X.Y is
your major Python version number.
</p>
<p>
Additionally, Python's <tt class="literal">/include</tt> subdirectory has to be added to your
include path.</p>
Additionally, Python's <tt class="literal">/include</tt> subdirectory has to be added
to your include path.
</p>
<p>
In a Jamfile, all the above boils down to:</p>
<pre class="programlisting"><tt class="literal">projectroot c:\projects\embedded_program ; # location of the program
In a Jamfile, all the above boils down to:
</p>
<pre class="programlisting">projectroot c:\projects\embedded_program ; # location of the program
# bring in the rules for python
SEARCH on python.jam = $(BOOST_BUILD_PATH) ;
@ -73,90 +81,121 @@ exe embedded_program # name of the executable
$(PYTHON_PROPERTIES)
&lt;library-path&gt;$(PYTHON_LIB_PATH)
&lt;find-library&gt;$(PYTHON_EMBEDDED_LIBRARY) ;
</tt></pre>
</pre>
<a name="embedding.getting_started"></a><h2>
<a name="id456277"></a>Getting started</h2>
<a name="id457409"></a>
Getting started
</h2>
<p>
Being able to build is nice, but there is nothing to build yet. Embedding
the Python interpreter into one of your C++ programs requires these 4
steps:</p>
Being able to build is nice, but there is nothing to build yet. Embedding the
Python interpreter into one of your C++ programs requires these 4 steps:
</p>
<div class="orderedlist"><ol type="1">
<li>
#include <tt class="literal">&lt;boost/python.hpp&gt;</tt><br><br>
#include <tt class="literal">&lt;boost/python.hpp&gt;</tt><br><br>
</li>
<li>
Call <a href="http://www.python.org/doc/current/api/initialization.html#l2h-652" target="_top">Py_Initialize</a>() to start the interpreter and create the <tt class="literal"><span class="underline">_main</span>_</tt> module.<br><br>
Call <a href="http://www.python.org/doc/current/api/initialization.html#l2h-652" target="_top">Py_Initialize</a>()
to start the interpreter and create the <tt class="literal"><span class="underline">_main</span>_</tt>
module.<br><br>
</li>
<li>
Call other Python C API routines to use the interpreter.<br><br>
Call other Python C API routines to use the interpreter.<br><br>
</li>
<li>
Call <a href="http://www.python.org/doc/current/api/initialization.html#l2h-656" target="_top">Py_Finalize</a>() to stop the interpreter and release its resources.
</li>
Call <a href="http://www.python.org/doc/current/api/initialization.html#l2h-656" target="_top">Py_Finalize</a>()
to stop the interpreter and release its resources.
</li>
</ol></div>
<p>
(Of course, there can be other C++ code between all of these steps.)</p>
<div class="blockquote"><blockquote class="blockquote"><p><span class="emphasis"><em><span class="bold"><b>Now that we can embed the interpreter in our programs, lets see how to put it to use...</b></span></em></span></p></blockquote></div>
(Of course, there can be other C++ code between all of these steps.)
</p>
<div class="blockquote"><blockquote class="blockquote"><p><span class="emphasis"><em><span class="bold"><b>Now that we can embed the interpreter in
our programs, lets see how to put it to use...</b></span></em></span></p></blockquote></div>
<div class="section" lang="en">
<div class="titlepage"><div><div><h3 class="title">
<a name="python.using_the_interpreter"></a>Using the interpreter</h3></div></div></div>
<p>
As you probably already know, objects in Python are reference-counted.
Naturally, the <tt class="literal">PyObject</tt>s of the Python/C API are also reference-counted.
There is a difference however. While the reference-counting is fully
automatic in Python, the Python/C API requires you to do it
<a href="http://www.python.org/doc/current/api/refcounts.html" target="_top">by hand</a>. This is
messy and especially hard to get right in the presence of C++ exceptions.
Fortunately Boost.Python provides the <a href="../../../../v2/handle.html" target="_top">handle</a> and
<a href="../../../../v2/object.html" target="_top">object</a> class templates to automate the process.</p>
Using the interpreterAs you probably already know, objects in Python are
reference-counted. Naturally, the <tt class="literal">PyObject</tt>s of the Python/C
API are also reference-counted. There is a difference however. While the
reference-counting is fully automatic in Python, the Python/C API requires
you to do it <a href="http://www.python.org/doc/current/api/refcounts.html" target="_top">by
hand</a>. This is messy and especially hard to get right in the presence
of C++ exceptions. Fortunately Boost.Python provides the <a href="../../../../v2/handle.html" target="_top">handle</a>
and <a href="../../../../v2/object.html" target="_top">object</a> class templates to
automate the process.
</p>
<a name="using_the_interpreter.reference_counting_handles_and_objects"></a><h2>
<a name="id456409"></a>Reference-counting handles and objects</h2>
<a name="id457544"></a>
Reference-counting handles and objects
</h2>
<p>
There are two ways in which a function in the Python/C API can return a
<tt class="literal">PyObject*</tt>: as a <span class="emphasis"><em>borrowed reference</em></span> or as a <span class="emphasis"><em>new reference</em></span>. Which of
these a function uses, is listed in that function's documentation. The two
require slightely different approaches to reference-counting but both can
be 'handled' by Boost.Python.</p>
There are two ways in which a function in the Python/C API can return a
<tt class="literal">PyObject*</tt>: as a <span class="emphasis"><em>borrowed reference</em></span>
or as a <span class="emphasis"><em>new reference</em></span>. Which of these a function uses,
is listed in that function's documentation. The two require slightely different
approaches to reference-counting but both can be 'handled' by Boost.Python.
</p>
<p>
For a function returning a <span class="emphasis"><em>borrowed reference</em></span> we'll have to tell the
<tt class="literal">handle</tt> that the <tt class="literal">PyObject*</tt> is borrowed with the aptly named
<a href="../../../../v2/handle.html#borrowed-spec" target="_top">borrowed</a> function. Two functions
returning borrowed references are <a href="http://www.python.org/doc/current/api/importing.html#l2h-125" target="_top">PyImport_AddModule</a> and <a href="http://www.python.org/doc/current/api/moduleObjects.html#l2h-594" target="_top">PyModule_GetDict</a>.
The former returns a reference to an already imported module, the latter
retrieves a module's namespace dictionary. Let's use them to retrieve the
namespace of the <tt class="literal"><span class="underline">_main</span>_</tt> module:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">object</span><span class="identifier"> main_module</span><span class="special">((</span><span class="identifier">
handle</span><span class="special">&lt;&gt;(</span><span class="identifier">borrowed</span><span class="special">(</span><a href="http://www.python.org/doc/current/api/importing.html#l2h-125" target="_top">PyImport_AddModule</a><span class="special">(</span><span class="string">"__main__"</span><span class="special">)))));</span><span class="identifier">
For a function returning a <span class="emphasis"><em>borrowed reference</em></span> we'll
have to tell the <tt class="literal">handle</tt> that the <tt class="literal">PyObject*</tt>
is borrowed with the aptly named <a href="../../../../v2/handle.html#borrowed-spec" target="_top">borrowed</a>
function. Two functions returning borrowed references are <a href="http://www.python.org/doc/current/api/importing.html#l2h-125" target="_top">PyImport_AddModule</a>
and <a href="http://www.python.org/doc/current/api/moduleObjects.html#l2h-594" target="_top">PyModule_GetDict</a>.
The former returns a reference to an already imported module, the latter
retrieves a module's namespace dictionary. Let's use them to retrieve the
namespace of the <tt class="literal"><span class="underline">_main</span>_</tt>
module:
</p>
<pre class="programlisting">
<span class="identifier">object</span> <span class="identifier">main_module</span><span class="special">((</span>
<span class="identifier">handle</span><span class="special">&lt;&gt;(</span><span class="identifier">borrowed</span><span class="special">(</span><a href="http://www.python.org/doc/current/api/importing.html#l2h-125" target="_top">PyImport_AddModule</a><span class="special">(</span><span class="string">"__main__"</span><span class="special">)))));</span>
object</span><span class="identifier"> main_namespace</span><span class="special"> =</span><span class="identifier"> main_module</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"__dict__"</span><span class="special">);</span></tt></pre>
<span class="identifier">object</span> <span class="identifier">main_namespace</span> <span class="special">=</span> <span class="identifier">main_module</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"__dict__"</span><span class="special">);</span>
</pre>
<p>
For a function returning a <span class="emphasis"><em>new reference</em></span> we can just create a <tt class="literal">handle</tt>
out of the raw <tt class="literal">PyObject*</tt> without wrapping it in a call to borrowed. One
such function that returns a new reference is <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55" target="_top">PyRun_String</a> which we'll
discuss in the next section.</p>
For a function returning a <span class="emphasis"><em>new reference</em></span> we can just
create a <tt class="literal">handle</tt> out of the raw <tt class="literal">PyObject*</tt>
without wrapping it in a call to borrowed. One such function that returns
a new reference is <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55" target="_top">PyRun_String</a>
which we'll discuss in the next section.
</p>
<div class="informaltable"><table class="table">
<colgroup><col></colgroup>
<tbody><tr><td class="blurb">
<span class="inlinemediaobject"><img src="../images/note.png"></span><span class="bold"><b>Handle is a class <span class="emphasis"><em>template</em></span>, so why haven't we been using any template parameters?</b></span><br><br><tt class="literal">handle</tt> has a single template parameter specifying the type of the managed object. This type is <tt class="literal">PyObject</tt> 99% of the time, so the parameter was defaulted to <tt class="literal">PyObject</tt> for convenience. Therefore we can use the shorthand <tt class="literal">handle&lt;&gt;</tt> instead of the longer, but equivalent, <tt class="literal">handle&lt;PyObject&gt;</tt>.
</td></tr></tbody>
<span class="inlinemediaobject"><img src="../images/note.png"></span> <span class="bold"><b>Handle is a class <span class="emphasis"><em>template</em></span>, so why
haven't we been using any template parameters?</b></span><br><br><tt class="literal">handle</tt> has a single template parameter specifying
the type of the managed object. This type is <tt class="literal">PyObject</tt>
99% of the time, so the parameter was defaulted to <tt class="literal">PyObject</tt>
for convenience. Therefore we can use the shorthand <tt class="literal">handle&lt;&gt;</tt>
instead of the longer, but equivalent, <tt class="literal">handle&lt;PyObject&gt;</tt>.
</td></tr></tbody>
</table></div>
<a name="using_the_interpreter.running_python_code"></a><h2>
<a name="id456714"></a>Running Python code</h2>
<a name="id457863"></a>
Running Python code
</h2>
<p>
To run Python code from C++ there is a family of functions in the API
starting with the PyRun prefix. You can find the full list of these
functions <a href="http://www.python.org/doc/current/api/veryhigh.html" target="_top">here</a>. They
all work similarly so we will look at only one of them, namely:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">PyObject</span><span class="special">*</span> <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55" target="_top">PyRun_String</a><span class="special">(</span><span class="keyword">char</span><span class="special"> *</span><span class="identifier">str</span><span class="special">,</span><span class="keyword"> int</span><span class="identifier"> start</span><span class="special">,</span><span class="identifier"> PyObject</span><span class="special"> *</span><span class="identifier">globals</span><span class="special">,</span><span class="identifier"> PyObject</span><span class="special"> *</span><span class="identifier">locals</span><span class="special">)</span></tt></pre>
<p><a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55" target="_top">PyRun_String</a> takes the code to execute as a null-terminated (C-style)
string in its <tt class="literal">str</tt> parameter. The function returns a new reference to a
Python object. Which object is returned depends on the <tt class="literal">start</tt> paramater.</p>
To run Python code from C++ there is a family of functions in the API starting
with the PyRun prefix. You can find the full list of these functions <a href="http://www.python.org/doc/current/api/veryhigh.html" target="_top">here</a>. They
all work similarly so we will look at only one of them, namely:
</p>
<pre class="programlisting">
<span class="identifier">PyObject</span><span class="special">*</span> <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55" target="_top">PyRun_String</a><span class="special">(</span><span class="keyword">char</span> <span class="special">*</span><span class="identifier">str</span><span class="special">,</span> <span class="keyword">int</span> <span class="identifier">start</span><span class="special">,</span> <span class="identifier">PyObject</span> <span class="special">*</span><span class="identifier">globals</span><span class="special">,</span> <span class="identifier">PyObject</span> <span class="special">*</span><span class="identifier">locals</span><span class="special">)</span>
</pre>
<p><a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55" target="_top">PyRun_String</a>
takes the code to execute as a null-terminated (C-style) string in its <tt class="literal">str</tt>
parameter. The function returns a new reference to a Python object. Which
object is returned depends on the <tt class="literal">start</tt> paramater.
</p>
<p>
The <tt class="literal">start</tt> parameter is the start symbol from the Python grammar to use
for interpreting the code. The possible values are:</p>
The <tt class="literal">start</tt> parameter is the start symbol from the Python
grammar to use for interpreting the code. The possible values are:
</p>
<div class="informaltable">
<h4>
<a name="id456876"></a><span class="table-title">Start symbols</span>
<a name="id458033"></a><span class="table-title">Start symbols</span>
</h4>
<table class="table">
<colgroup>
@ -165,178 +204,215 @@ for interpreting the code. The possible values are:</p>
</colgroup>
<thead><tr>
<th><a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-58" target="_top">Py_eval_input</a></th>
<th>for interpreting isolated expressions</th>
<th>for
interpreting isolated expressions</th>
</tr></thead>
<tbody>
<tr>
<td><a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-59" target="_top">Py_file_input</a></td>
<td>for interpreting sequences of statements</td>
<td>for
interpreting sequences of statements</td>
</tr>
<tr>
<td><a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-60" target="_top">Py_single_input</a></td>
<td>for interpreting a single statement</td>
<td>for
interpreting a single statement</td>
</tr>
</tbody>
</table>
</div>
<p>
When using <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-58" target="_top">Py_eval_input</a>, the input string must contain a single expression
and its result is returned. When using <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-59" target="_top">Py_file_input</a>, the string can
contain an abitrary number of statements and None is returned.
<a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-60" target="_top">Py_single_input</a> works in the same way as <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-59" target="_top">Py_file_input</a> but only accepts a
single statement.</p>
When using <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-58" target="_top">Py_eval_input</a>,
the input string must contain a single expression and its result is returned.
When using <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-59" target="_top">Py_file_input</a>,
the string can contain an abitrary number of statements and None is returned.
<a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-60" target="_top">Py_single_input</a>
works in the same way as <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-59" target="_top">Py_file_input</a>
but only accepts a single statement.
</p>
<p>
Lastly, the <tt class="literal">globals</tt> and <tt class="literal">locals</tt> parameters are Python dictionaries
containing the globals and locals of the context in which to run the code.
For most intents and purposes you can use the namespace dictionary of the
<tt class="literal"><span class="underline">_main</span>_</tt> module for both parameters.</p>
Lastly, the <tt class="literal">globals</tt> and <tt class="literal">locals</tt> parameters
are Python dictionaries containing the globals and locals of the context
in which to run the code. For most intents and purposes you can use the namespace
dictionary of the <tt class="literal"><span class="underline">_main</span>_</tt>
module for both parameters.
</p>
<p>
We have already seen how to get the <tt class="literal"><span class="underline">_main</span>_</tt> module's namespace so let's
run some Python code in it:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">object</span><span class="identifier"> main_module</span><span class="special">((</span><span class="identifier">
handle</span><span class="special">&lt;&gt;(</span><span class="identifier">borrowed</span><span class="special">(</span><a href="http://www.python.org/doc/current/api/importing.html#l2h-125" target="_top">PyImport_AddModule</a><span class="special">(</span><span class="string">"__main__"</span><span class="special">)))));</span><span class="identifier">
We have already seen how to get the <tt class="literal"><span class="underline">_main</span>_</tt>
module's namespace so let's run some Python code in it:
</p>
<pre class="programlisting">
<span class="identifier">object</span> <span class="identifier">main_module</span><span class="special">((</span>
<span class="identifier">handle</span><span class="special">&lt;&gt;(</span><span class="identifier">borrowed</span><span class="special">(</span><a href="http://www.python.org/doc/current/api/importing.html#l2h-125" target="_top">PyImport_AddModule</a><span class="special">(</span><span class="string">"__main__"</span><span class="special">)))));</span>
object</span><span class="identifier"> main_namespace</span><span class="special"> =</span><span class="identifier"> main_module</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"__dict__"</span><span class="special">);</span><span class="identifier">
<span class="identifier">object</span> <span class="identifier">main_namespace</span> <span class="special">=</span> <span class="identifier">main_module</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"__dict__"</span><span class="special">);</span>
handle</span><span class="special">&lt;&gt;</span><span class="identifier"> ignored</span><span class="special">((</span><a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55" target="_top">PyRun_String</a><span class="special">(</span><span class="string">
<span class="identifier">handle</span><span class="special">&lt;&gt;</span> <span class="identifier">ignored</span><span class="special">((</span><a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55" target="_top">PyRun_String</a><span class="special">(</span>
"hello = file('hello.txt', 'w')\n"</span><span class="string">
"hello.write('Hello world!')\n"</span><span class="string">
"hello.close()"</span><span class="special">
<span class="string">"hello = file('hello.txt', 'w')\n"</span>
<span class="string">"hello.write('Hello world!')\n"</span>
<span class="string">"hello.close()"</span>
,</span> <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-59" target="_top">Py_file_input</a><span class="special">
,</span><span class="identifier"> main_namespace</span><span class="special">.</span><span class="identifier">ptr</span><span class="special">()</span><span class="special">
,</span><span class="identifier"> main_namespace</span><span class="special">.</span><span class="identifier">ptr</span><span class="special">())</span><span class="special">
));</span></tt></pre>
<span class="special">,</span> <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-59" target="_top">Py_file_input</a>
<span class="special">,</span> <span class="identifier">main_namespace</span><span class="special">.</span><span class="identifier">ptr</span><span class="special">()</span>
<span class="special">,</span> <span class="identifier">main_namespace</span><span class="special">.</span><span class="identifier">ptr</span><span class="special">())</span>
<span class="special">));</span>
</pre>
<p>
Because the Python/C API doesn't know anything about <tt class="literal">object</tt>s, we used
the object's <tt class="literal">ptr</tt> member function to retrieve the <tt class="literal">PyObject*</tt>.</p>
Because the Python/C API doesn't know anything about <tt class="literal">object</tt>s,
we used the object's <tt class="literal">ptr</tt> member function to retrieve the
<tt class="literal">PyObject*</tt>.
</p>
<p>
This should create a file called 'hello.txt' in the current directory
containing a phrase that is well-known in programming circles.</p>
This should create a file called 'hello.txt' in the current directory containing
a phrase that is well-known in programming circles.
</p>
<div class="informaltable"><table class="table">
<colgroup><col></colgroup>
<tbody><tr><td class="blurb">
<span class="inlinemediaobject"><img src="../images/note.png"></span><span class="bold"><b>Note</b></span> that we wrap the return value of <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55" target="_top">PyRun_String</a> in a
(nameless) <tt class="literal">handle</tt> even though we are not interested in it. If we didn't
do this, the the returned object would be kept alive unnecessarily. Unless
you want to be a Dr. Frankenstein, always wrap <tt class="literal">PyObject*</tt>s in <tt class="literal">handle</tt>s.
</td></tr></tbody>
<span class="inlinemediaobject"><img src="../images/note.png"></span> <span class="bold"><b>Note</b></span> that we wrap the return value of <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55" target="_top">PyRun_String</a>
in a (nameless) <tt class="literal">handle</tt> even though we are not interested
in it. If we didn't do this, the the returned object would be kept
alive unnecessarily. Unless you want to be a Dr. Frankenstein, always
wrap <tt class="literal">PyObject*</tt>s in <tt class="literal">handle</tt>s.
</td></tr></tbody>
</table></div>
<a name="using_the_interpreter.beyond_handles"></a><h2>
<a name="id457324"></a>Beyond handles</h2>
<a name="id458506"></a>
Beyond handles
</h2>
<p>
It's nice that <tt class="literal">handle</tt> manages the reference counting details for us, but
other than that it doesn't do much. Often we'd like to have a more useful
class to manipulate Python objects. But we have already seen such a class
above, and in the <a href="object.html" target="_top">previous section</a>: the aptly
named <tt class="literal">object</tt> class and it's derivatives. We've already seen that they
can be constructed from a <tt class="literal">handle</tt>. The following examples should further
illustrate this fact:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">object</span><span class="identifier"> main_module</span><span class="special">((</span><span class="identifier">
handle</span><span class="special">&lt;&gt;(</span><span class="identifier">borrowed</span><span class="special">(</span><a href="http://www.python.org/doc/current/api/importing.html#l2h-125" target="_top">PyImport_AddModule</a><span class="special">(</span><span class="string">"__main__"</span><span class="special">)))));</span><span class="identifier">
It's nice that <tt class="literal">handle</tt> manages the reference counting details
for us, but other than that it doesn't do much. Often we'd like to have a
more useful class to manipulate Python objects. But we have already seen
such a class above, and in the <a href="object.html" target="_top">previous section</a>:
the aptly named <tt class="literal">object</tt> class and it's derivatives. We've
already seen that they can be constructed from a <tt class="literal">handle</tt>.
The following examples should further illustrate this fact:
</p>
<pre class="programlisting">
<span class="identifier">object</span> <span class="identifier">main_module</span><span class="special">((</span>
<span class="identifier">handle</span><span class="special">&lt;&gt;(</span><span class="identifier">borrowed</span><span class="special">(</span><a href="http://www.python.org/doc/current/api/importing.html#l2h-125" target="_top">PyImport_AddModule</a><span class="special">(</span><span class="string">"__main__"</span><span class="special">)))));</span>
object</span><span class="identifier"> main_namespace</span><span class="special"> =</span><span class="identifier"> main_module</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"__dict__"</span><span class="special">);</span><span class="identifier">
<span class="identifier">object</span> <span class="identifier">main_namespace</span> <span class="special">=</span> <span class="identifier">main_module</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"__dict__"</span><span class="special">);</span>
handle</span><span class="special">&lt;&gt;</span><span class="identifier"> ignored</span><span class="special">((</span><a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55" target="_top">PyRun_String</a><span class="special">(</span><span class="string">
<span class="identifier">handle</span><span class="special">&lt;&gt;</span> <span class="identifier">ignored</span><span class="special">((</span><a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55" target="_top">PyRun_String</a><span class="special">(</span>
"result = 5 ** 2"</span><span class="special">
<span class="string">"result = 5 ** 2"</span>
,</span> <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-59" target="_top">Py_file_input</a><span class="special">
,</span><span class="identifier"> main_namespace</span><span class="special">.</span><span class="identifier">ptr</span><span class="special">()</span><span class="special">
,</span><span class="identifier"> main_namespace</span><span class="special">.</span><span class="identifier">ptr</span><span class="special">())</span><span class="special">
));</span><span class="keyword">
<span class="special">,</span> <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-59" target="_top">Py_file_input</a>
<span class="special">,</span> <span class="identifier">main_namespace</span><span class="special">.</span><span class="identifier">ptr</span><span class="special">()</span>
<span class="special">,</span> <span class="identifier">main_namespace</span><span class="special">.</span><span class="identifier">ptr</span><span class="special">())</span>
<span class="special">));</span>
int</span><span class="identifier"> five_squared</span><span class="special"> =</span><span class="identifier"> extract</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;(</span><span class="identifier">main_namespace</span><span class="special">[</span><span class="string">"result"</span><span class="special">]);</span></tt></pre>
<span class="keyword">int</span> <span class="identifier">five_squared</span> <span class="special">=</span> <span class="identifier">extract</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;(</span><span class="identifier">main_namespace</span><span class="special">[</span><span class="string">"result"</span><span class="special">]);</span>
</pre>
<p>
Here we create a dictionary object for the <tt class="literal"><span class="underline">_main</span>_</tt> module's namespace.
Then we assign 5 squared to the result variable and read this variable from
the dictionary. Another way to achieve the same result is to let
<a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55" target="_top">PyRun_String</a> return the result directly with <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-58" target="_top">Py_eval_input</a>:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">object</span><span class="identifier"> result</span><span class="special">((</span><span class="identifier">handle</span><span class="special">&lt;&gt;(</span>
    <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55" target="_top">PyRun_String</a><span class="special">(</span><span class="string">"5 ** 2"</span><span class="special">
,</span> <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-58" target="_top">Py_eval_input</a><span class="special">
,</span><span class="identifier"> main_namespace</span><span class="special">.</span><span class="identifier">ptr</span><span class="special">()</span><span class="special">
,</span><span class="identifier"> main_namespace</span><span class="special">.</span><span class="identifier">ptr</span><span class="special">()))</span><span class="special">
));</span><span class="keyword">
Here we create a dictionary object for the <tt class="literal"><span class="underline">_main</span>_</tt>
module's namespace. Then we assign 5 squared to the result variable and read
this variable from the dictionary. Another way to achieve the same result
is to let <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55" target="_top">PyRun_String</a>
return the result directly with <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-58" target="_top">Py_eval_input</a>:
</p>
<pre class="programlisting">
<span class="identifier">object</span> <span class="identifier">result</span><span class="special">((</span><span class="identifier">handle</span><span class="special">&lt;&gt;(</span>
<a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55" target="_top">PyRun_String</a><span class="special">(</span><span class="string">"5 ** 2"</span>
<span class="special">,</span> <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-58" target="_top">Py_eval_input</a>
<span class="special">,</span> <span class="identifier">main_namespace</span><span class="special">.</span><span class="identifier">ptr</span><span class="special">()</span>
<span class="special">,</span> <span class="identifier">main_namespace</span><span class="special">.</span><span class="identifier">ptr</span><span class="special">()))</span>
<span class="special">));</span>
int</span><span class="identifier"> five_squared</span><span class="special"> =</span><span class="identifier"> extract</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;(</span><span class="identifier">result</span><span class="special">);</span></tt></pre>
<span class="keyword">int</span> <span class="identifier">five_squared</span> <span class="special">=</span> <span class="identifier">extract</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;(</span><span class="identifier">result</span><span class="special">);</span>
</pre>
<div class="informaltable"><table class="table">
<colgroup><col></colgroup>
<tbody><tr><td class="blurb">
<span class="inlinemediaobject"><img src="../images/note.png"></span><span class="bold"><b>Note</b></span> that <tt class="literal">object</tt>'s member function to return the wrapped
<tt class="literal">PyObject*</tt> is called <tt class="literal">ptr</tt> instead of <tt class="literal">get</tt>. This makes sense if you
take into account the different functions that <tt class="literal">object</tt> and <tt class="literal">handle</tt>
perform.
</td></tr></tbody>
<span class="inlinemediaobject"><img src="../images/note.png"></span> <span class="bold"><b>Note</b></span> that <tt class="literal">object</tt>'s member
function to return the wrapped <tt class="literal">PyObject*</tt> is called
<tt class="literal">ptr</tt> instead of <tt class="literal">get</tt>. This makes
sense if you take into account the different functions that <tt class="literal">object</tt>
and <tt class="literal">handle</tt> perform. </td></tr></tbody>
</table></div>
<a name="using_the_interpreter.exception_handling"></a><h2>
<a name="id457906"></a>Exception handling</h2>
<a name="id459120"></a>
Exception handling
</h2>
<p>
If an exception occurs in the execution of some Python code, the <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55" target="_top">PyRun_String</a>
function returns a null pointer. Constructing a <tt class="literal">handle</tt> out of this null
pointer throws <a href="../../../../v2/errors.html#error_already_set-spec" target="_top">error_already_set</a>,
so basically, the Python exception is automatically translated into a
C++ exception when using <tt class="literal">handle</tt>:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">try</span><span class="special">
{</span><span class="identifier">
object</span><span class="identifier"> result</span><span class="special">((</span><span class="identifier">handle</span><span class="special">&lt;&gt;(</span><a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55" target="_top">PyRun_String</a><span class="special">(</span><span class="string">
"5/0"</span><span class="special">
,</span> <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-58" target="_top">Py_eval_input</a><span class="special">
,</span><span class="identifier"> main_namespace</span><span class="special">.</span><span class="identifier">ptr</span><span class="special">()</span><span class="special">
,</span><span class="identifier"> main_namespace</span><span class="special">.</span><span class="identifier">ptr</span><span class="special">()))</span><span class="special">
));</span><span class="comment">
If an exception occurs in the execution of some Python code, the <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55" target="_top">PyRun_String</a>
function returns a null pointer. Constructing a <tt class="literal">handle</tt>
out of this null pointer throws <a href="../../../../v2/errors.html#error_already_set-spec" target="_top">error_already_set</a>,
so basically, the Python exception is automatically translated into a C++
exception when using <tt class="literal">handle</tt>:
</p>
<pre class="programlisting">
<span class="keyword">try</span>
<span class="special">{</span>
<span class="identifier">object</span> <span class="identifier">result</span><span class="special">((</span><span class="identifier">handle</span><span class="special">&lt;&gt;(</span><a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55" target="_top">PyRun_String</a><span class="special">(</span>
<span class="string">"5/0"</span>
<span class="special">,</span> <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-58" target="_top">Py_eval_input</a>
<span class="special">,</span> <span class="identifier">main_namespace</span><span class="special">.</span><span class="identifier">ptr</span><span class="special">()</span>
<span class="special">,</span> <span class="identifier">main_namespace</span><span class="special">.</span><span class="identifier">ptr</span><span class="special">()))</span>
<span class="special">));</span>
// execution will never get here:
</span><span class="keyword"> int</span><span class="identifier"> five_divided_by_zero</span><span class="special"> =</span><span class="identifier"> extract</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;(</span><span class="identifier">result</span><span class="special">);</span><span class="special">
}</span><span class="keyword">
catch</span><span class="special">(</span><span class="identifier">error_already_set</span><span class="special">)</span><span class="special">
{</span><span class="comment">
// handle the exception in some way
</span><span class="special">}</span></tt></pre>
<span class="comment">// execution will never get here:
</span> <span class="keyword">int</span> <span class="identifier">five_divided_by_zero</span> <span class="special">=</span> <span class="identifier">extract</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;(</span><span class="identifier">result</span><span class="special">);</span>
<span class="special">}</span>
<span class="keyword">catch</span><span class="special">(</span><span class="identifier">error_already_set</span><span class="special">)</span>
<span class="special">{</span>
<span class="comment">// handle the exception in some way
</span><span class="special">}</span>
</pre>
<p>
The <tt class="literal">error_already_set</tt> exception class doesn't carry any information in itself.
To find out more about the Python exception that occurred, you need to use the
<a href="http://www.python.org/doc/api/exceptionHandling.html" target="_top">exception handling functions</a>
of the Python/C API in your catch-statement. This can be as simple as calling
<a href="http://www.python.org/doc/api/exceptionHandling.html#l2h-70" target="_top">PyErr_Print()</a> to
print the exception's traceback to the console, or comparing the type of the
exception with those of the <a href="http://www.python.org/doc/api/standardExceptions.html" target="_top">standard exceptions</a>:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">catch</span><span class="special">(</span><span class="identifier">error_already_set</span><span class="special">)</span><span class="special">
{</span><span class="keyword">
if</span><span class="special"> (</span><span class="identifier">PyErr_ExceptionMatches</span><span class="special">(</span><span class="identifier">PyExc_ZeroDivisionError</span><span class="special">))</span><span class="special">
{</span><span class="comment">
// handle ZeroDivisionError specially
</span><span class="special"> }</span><span class="keyword">
else</span><span class="special">
{</span><span class="comment">
// print all other errors to stderr
</span><span class="identifier"> PyErr_Print</span><span class="special">();</span><span class="special">
}</span><span class="special">
}</span></tt></pre>
The <tt class="literal">error_already_set</tt> exception class doesn't carry any
information in itself. To find out more about the Python exception that occurred,
you need to use the <a href="http://www.python.org/doc/api/exceptionHandling.html" target="_top">exception
handling functions</a> of the Python/C API in your catch-statement. This
can be as simple as calling <a href="http://www.python.org/doc/api/exceptionHandling.html#l2h-70" target="_top">PyErr_Print()</a>
to print the exception's traceback to the console, or comparing the type
of the exception with those of the <a href="http://www.python.org/doc/api/standardExceptions.html" target="_top">standard
exceptions</a>:
</p>
<pre class="programlisting">
<span class="keyword">catch</span><span class="special">(</span><span class="identifier">error_already_set</span><span class="special">)</span>
<span class="special">{</span>
<span class="keyword">if</span> <span class="special">(</span><span class="identifier">PyErr_ExceptionMatches</span><span class="special">(</span><span class="identifier">PyExc_ZeroDivisionError</span><span class="special">))</span>
<span class="special">{</span>
<span class="comment">// handle ZeroDivisionError specially
</span> <span class="special">}</span>
<span class="keyword">else</span>
<span class="special">{</span>
<span class="comment">// print all other errors to stderr
</span> <span class="identifier">PyErr_Print</span><span class="special">();</span>
<span class="special">}</span>
<span class="special">}</span>
</pre>
<p>
(To retrieve even more information from the exception you can use some of the other
exception handling functions listed <a href="http://www.python.org/doc/api/exceptionHandling.html" target="_top">here</a>.)</p>
(To retrieve even more information from the exception you can use some of
the other exception handling functions listed <a href="http://www.python.org/doc/api/exceptionHandling.html" target="_top">here</a>.)
</p>
<p>
If you'd rather not have <tt class="literal">handle</tt> throw a C++ exception when it is constructed, you
can use the <a href="../../../../v2/handle.html#allow_null-spec" target="_top">allow_null</a> function in the same
way you'd use borrowed:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">handle</span><span class="special">&lt;&gt;</span><span class="identifier"> result</span><span class="special">((</span><span class="identifier">allow_null</span><span class="special">(</span><a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55" target="_top">PyRun_String</a><span class="special">(</span><span class="string">
"5/0"</span><span class="special">
,</span> <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-58" target="_top">Py_eval_input</a><span class="special">
,</span><span class="identifier"> main_namespace</span><span class="special">.</span><span class="identifier">ptr</span><span class="special">()</span><span class="special">
,</span><span class="identifier"> main_namespace</span><span class="special">.</span><span class="identifier">ptr</span><span class="special">()))));</span><span class="keyword">
If you'd rather not have <tt class="literal">handle</tt> throw a C++ exception
when it is constructed, you can use the <a href="../../../../v2/handle.html#allow_null-spec" target="_top">allow_null</a>
function in the same way you'd use borrowed:
</p>
<pre class="programlisting">
<span class="identifier">handle</span><span class="special">&lt;&gt;</span> <span class="identifier">result</span><span class="special">((</span><span class="identifier">allow_null</span><span class="special">(</span><a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55" target="_top">PyRun_String</a><span class="special">(</span>
<span class="string">"5/0"</span>
<span class="special">,</span> <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-58" target="_top">Py_eval_input</a>
<span class="special">,</span> <span class="identifier">main_namespace</span><span class="special">.</span><span class="identifier">ptr</span><span class="special">()</span>
<span class="special">,</span> <span class="identifier">main_namespace</span><span class="special">.</span><span class="identifier">ptr</span><span class="special">()))));</span>
if</span><span class="special"> (!</span><span class="identifier">result</span><span class="special">)</span><span class="comment">
// Python exception occurred
</span><span class="keyword">else</span><span class="comment">
// everything went okay, it's safe to use the result
</span></tt></pre>
<span class="keyword">if</span> <span class="special">(!</span><span class="identifier">result</span><span class="special">)</span>
<span class="comment">// Python exception occurred
</span><span class="keyword">else</span>
<span class="comment">// everything went okay, it's safe to use the result
</span></pre>
</div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><small>Copyright © 2002-2005 Joel de Guzman, David Abrahams</small></td>
<td align="right"><small>Copyright © 2002-2005 Joel
de Guzman, David Abrahams</small></td>
</tr></table>
<hr>
<div class="spirit-nav">

View File

@ -26,25 +26,32 @@
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="python.exception"></a> Exception Translation</h2></div></div></div>
<p>
All C++ exceptions must be caught at the boundary with Python code. This
boundary is the point where C++ meets Python. Boost.Python provides a
default exception handler that translates selected standard exceptions,
then gives up:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">raise</span><span class="identifier"> RuntimeError</span><span class="special">,</span><span class="char"> 'unidentifiable C++ Exception'</span></tt></pre>
Exception TranslationAll C++ exceptions must be caught at the boundary with
Python code. This boundary is the point where C++ meets Python. Boost.Python
provides a default exception handler that translates selected standard exceptions,
then gives up:
</p>
<pre class="programlisting">
<span class="keyword">raise</span> <span class="identifier">RuntimeError</span><span class="special">,</span> <span class="string">'unidentifiable C++ Exception'</span>
</pre>
<p>
Users may provide custom translation. Here's an example:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">struct</span><span class="identifier"> PodBayDoorException</span><span class="special">;</span><span class="keyword">
void</span><span class="identifier"> translator</span><span class="special">(</span><span class="identifier">PodBayDoorException</span><span class="keyword"> const</span><span class="special">&amp;</span><span class="identifier"> x</span><span class="special">)</span><span class="special"> {</span><span class="identifier">
PyErr_SetString</span><span class="special">(</span><span class="identifier">PyExc_UserWarning</span><span class="special">,</span><span class="string"> "I'm sorry Dave..."</span><span class="special">);</span><span class="special">
}</span><span class="identifier">
BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">kubrick</span><span class="special">)</span><span class="special"> {</span><span class="identifier">
register_exception_translator</span><span class="special">&lt;</span><span class="identifier">
PodBayDoorException</span><span class="special">&gt;(</span><span class="identifier">translator</span><span class="special">);</span><span class="special">
...</span></tt></pre>
Users may provide custom translation. Here's an example:
</p>
<pre class="programlisting">
<span class="identifier">struct</span> <span class="identifier">PodBayDoorException</span><span class="special">;</span>
<span class="identifier">void</span> <span class="identifier">translator</span><span class="special">(</span><span class="identifier">PodBayDoorException</span> <span class="identifier">const</span><span class="special">&amp;</span> <span class="identifier">x</span><span class="special">)</span> <span class="special">{</span>
<span class="identifier">PyErr_SetString</span><span class="special">(</span><span class="identifier">PyExc_UserWarning</span><span class="special">,</span> <span class="string">"I'm sorry Dave..."</span><span class="special">);</span>
<span class="special">}</span>
<span class="identifier">BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">kubrick</span><span class="special">)</span> <span class="special">{</span>
<span class="identifier">register_exception_translator</span><span class="special">&lt;</span>
<span class="identifier">PodBayDoorException</span><span class="special">&gt;(</span><span class="identifier">translator</span><span class="special">);</span>
<span class="special">...</span>
</pre>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><small>Copyright © 2002-2005 Joel de Guzman, David Abrahams</small></td>
<td align="right"><small>Copyright © 2002-2005 Joel
de Guzman, David Abrahams</small></td>
</tr></table>
<hr>
<div class="spirit-nav">

View File

@ -35,284 +35,373 @@
<dt><span class="section"><a href="exposing.html#python.class_operators_special_functions">Class Operators/Special Functions</a></span></dt>
</dl></div>
<p>
Now let's expose a C++ class to Python.</p>
Exposing ClassesNow let's expose a C++ class to Python.
</p>
<p>
Consider a C++ class/struct that we want to expose to Python:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">struct</span><span class="identifier"> World</span><span class="special">
{</span><span class="keyword">
void</span><span class="identifier"> set</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="identifier"> msg</span><span class="special">)</span><span class="special"> {</span><span class="keyword"> this</span><span class="special">-&gt;</span><span class="identifier">msg</span><span class="special"> =</span><span class="identifier"> msg</span><span class="special">;</span><span class="special"> }</span><span class="identifier">
std</span><span class="special">::</span><span class="identifier">string</span><span class="identifier"> greet</span><span class="special">()</span><span class="special"> {</span><span class="keyword"> return</span><span class="identifier"> msg</span><span class="special">;</span><span class="special"> }</span><span class="identifier">
std</span><span class="special">::</span><span class="identifier">string</span><span class="identifier"> msg</span><span class="special">;</span><span class="special">
};</span></tt></pre>
Consider a C++ class/struct that we want to expose to Python:
</p>
<pre class="programlisting">
<span class="keyword">struct</span> <span class="identifier">World</span>
<span class="special">{</span>
<span class="keyword">void</span> <span class="identifier">set</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">msg</span><span class="special">)</span> <span class="special">{</span> <span class="keyword">this</span><span class="special">-&gt;</span><span class="identifier">msg</span> <span class="special">=</span> <span class="identifier">msg</span><span class="special">;</span> <span class="special">}</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">greet</span><span class="special">()</span> <span class="special">{</span> <span class="keyword">return</span> <span class="identifier">msg</span><span class="special">;</span> <span class="special">}</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">msg</span><span class="special">;</span>
<span class="special">};</span>
</pre>
<p>
We can expose this to Python by writing a corresponding Boost.Python
C++ Wrapper:</p>
<pre class="programlisting"><tt class="literal"><span class="preprocessor">#include</span><span class="special"> &lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">python</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span><span class="keyword">
using</span><span class="keyword"> namespace</span><span class="identifier"> boost</span><span class="special">::</span><span class="identifier">python</span><span class="special">;</span><span class="identifier">
We can expose this to Python by writing a corresponding Boost.Python C++ Wrapper:
</p>
<pre class="programlisting">
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">python</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="keyword">using</span> <span class="keyword">namespace</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">python</span><span class="special">;</span>
BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">hello</span><span class="special">)</span><span class="special">
{</span><span class="identifier">
class_</span><span class="special">&lt;</span><span class="identifier">World</span><span class="special">&gt;(</span><span class="string">"World"</span><span class="special">)</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"greet"</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">World</span><span class="special">::</span><span class="identifier">greet</span><span class="special">)</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"set"</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">World</span><span class="special">::</span><span class="identifier">set</span><span class="special">)</span><span class="special">
;</span><span class="special">
}</span></tt></pre>
<span class="identifier">BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">hello</span><span class="special">)</span>
<span class="special">{</span>
<span class="identifier">class_</span><span class="special">&lt;</span><span class="identifier">World</span><span class="special">&gt;(</span><span class="string">"World"</span><span class="special">)</span>
<span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"greet"</span><span class="special">,</span> <span class="special">&amp;</span><span class="identifier">World</span><span class="special">::</span><span class="identifier">greet</span><span class="special">)</span>
<span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"set"</span><span class="special">,</span> <span class="special">&amp;</span><span class="identifier">World</span><span class="special">::</span><span class="identifier">set</span><span class="special">)</span>
<span class="special">;</span>
<span class="special">}</span>
</pre>
<p>
Here, we wrote a C++ class wrapper that exposes the member functions
<tt class="literal">greet</tt> and <tt class="literal">set</tt>. Now, after building our module as a shared library, we
may use our class <tt class="literal">World</tt> in Python. Here's a sample Python session:</p>
Here, we wrote a C++ class wrapper that exposes the member functions <tt class="literal">greet</tt>
and <tt class="literal">set</tt>. Now, after building our module as a shared library,
we may use our class <tt class="literal">World</tt> in Python. Here's a sample Python
session:
</p>
<p></p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="keyword"> import</span><span class="identifier"> hello</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> planet</span><span class="special"> =</span><span class="identifier"> hello</span><span class="special">.</span><span class="identifier">World</span><span class="special">()</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> planet</span><span class="special">.</span><span class="identifier">set</span><span class="special">(</span><span class="string">'howdy'</span><span class="special">)</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> planet</span><span class="special">.</span><span class="identifier">greet</span><span class="special">()</span><span class="string">
'howdy'</span></tt></pre>
<pre class="programlisting">
<span class="special">&gt;&gt;&gt;</span> <span class="keyword">import</span> <span class="identifier">hello</span>
<span class="special">&gt;&gt;&gt;</span> <span class="identifier">planet</span> <span class="special">=</span> <span class="identifier">hello</span><span class="special">.</span><span class="identifier">World</span><span class="special">()</span>
<span class="special">&gt;&gt;&gt;</span> <span class="identifier">planet</span><span class="special">.</span><span class="identifier">set</span><span class="special">(</span><span class="string">'howdy'</span><span class="special">)</span>
<span class="special">&gt;&gt;&gt;</span> <span class="identifier">planet</span><span class="special">.</span><span class="identifier">greet</span><span class="special">()</span>
<span class="string">'howdy'</span>
</pre>
<div class="section" lang="en">
<div class="titlepage"><div><div><h3 class="title">
<a name="python.constructors"></a>Constructors</h3></div></div></div>
<p>
Our previous example didn't have any explicit constructors.
Since <tt class="literal">World</tt> is declared as a plain struct, it has an implicit default
constructor. Boost.Python exposes the default constructor by default,
which is why we were able to write</p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="identifier"> planet</span><span class="special"> =</span><span class="identifier"> hello</span><span class="special">.</span><span class="identifier">World</span><span class="special">()</span></tt></pre>
ConstructorsOur previous example didn't have any explicit constructors. Since
<tt class="literal">World</tt> is declared as a plain struct, it has an implicit
default constructor. Boost.Python exposes the default constructor by default,
which is why we were able to write
</p>
<pre class="programlisting">
<span class="special">&gt;&gt;&gt;</span> <span class="identifier">planet</span> <span class="special">=</span> <span class="identifier">hello</span><span class="special">.</span><span class="identifier">World</span><span class="special">()</span>
</pre>
<p>
We may wish to wrap a class with a non-default constructor. Let us
build on our previous example:</p>
We may wish to wrap a class with a non-default constructor. Let us build
on our previous example:
</p>
<p></p>
<pre class="programlisting"><tt class="literal"><span class="keyword">struct</span><span class="identifier"> World</span><span class="special">
{</span><span class="identifier">
World</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="identifier"> msg</span><span class="special">):</span><span class="identifier"> msg</span><span class="special">(</span><span class="identifier">msg</span><span class="special">)</span><span class="special"> {}</span><span class="comment"> // added constructor
</span><span class="keyword"> void</span><span class="identifier"> set</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="identifier"> msg</span><span class="special">)</span><span class="special"> {</span><span class="keyword"> this</span><span class="special">-&gt;</span><span class="identifier">msg</span><span class="special"> =</span><span class="identifier"> msg</span><span class="special">;</span><span class="special"> }</span><span class="identifier">
std</span><span class="special">::</span><span class="identifier">string</span><span class="identifier"> greet</span><span class="special">()</span><span class="special"> {</span><span class="keyword"> return</span><span class="identifier"> msg</span><span class="special">;</span><span class="special"> }</span><span class="identifier">
std</span><span class="special">::</span><span class="identifier">string</span><span class="identifier"> msg</span><span class="special">;</span><span class="special">
};</span></tt></pre>
<pre class="programlisting">
<span class="keyword">struct</span> <span class="identifier">World</span>
<span class="special">{</span>
<span class="identifier">World</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">msg</span><span class="special">):</span> <span class="identifier">msg</span><span class="special">(</span><span class="identifier">msg</span><span class="special">)</span> <span class="special">{}</span> <span class="comment">// added constructor
</span> <span class="keyword">void</span> <span class="identifier">set</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">msg</span><span class="special">)</span> <span class="special">{</span> <span class="keyword">this</span><span class="special">-&gt;</span><span class="identifier">msg</span> <span class="special">=</span> <span class="identifier">msg</span><span class="special">;</span> <span class="special">}</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">greet</span><span class="special">()</span> <span class="special">{</span> <span class="keyword">return</span> <span class="identifier">msg</span><span class="special">;</span> <span class="special">}</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">msg</span><span class="special">;</span>
<span class="special">};</span>
</pre>
<p>
This time <tt class="literal">World</tt> has no default constructor; our previous
wrapping code would fail to compile when the library tried to expose
it. We have to tell <tt class="literal">class_&lt;World&gt;</tt> about the constructor we want to
expose instead.</p>
<pre class="programlisting"><tt class="literal"><span class="preprocessor">#include</span><span class="special"> &lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">python</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span><span class="keyword">
using</span><span class="keyword"> namespace</span><span class="identifier"> boost</span><span class="special">::</span><span class="identifier">python</span><span class="special">;</span><span class="identifier">
This time <tt class="literal">World</tt> has no default constructor; our previous
wrapping code would fail to compile when the library tried to expose it.
We have to tell <tt class="literal">class_&lt;World&gt;</tt> about the constructor
we want to expose instead.
</p>
<pre class="programlisting">
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">python</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="keyword">using</span> <span class="keyword">namespace</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">python</span><span class="special">;</span>
BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">hello</span><span class="special">)</span><span class="special">
{</span><span class="identifier">
class_</span><span class="special">&lt;</span><span class="identifier">World</span><span class="special">&gt;(</span><span class="string">"World"</span><span class="special">,</span><span class="identifier"> init</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&gt;())</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"greet"</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">World</span><span class="special">::</span><span class="identifier">greet</span><span class="special">)</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"set"</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">World</span><span class="special">::</span><span class="identifier">set</span><span class="special">)</span><span class="special">
;</span><span class="special">
}</span></tt></pre>
<p><tt class="literal">init&lt;std::string&gt;()</tt> exposes the constructor taking in a
<tt class="literal">std::string</tt> (in Python, constructors are spelled
"<tt class="literal">"<span class="underline">_init</span>_"</tt>").</p>
<span class="identifier">BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">hello</span><span class="special">)</span>
<span class="special">{</span>
<span class="identifier">class_</span><span class="special">&lt;</span><span class="identifier">World</span><span class="special">&gt;(</span><span class="string">"World"</span><span class="special">,</span> <span class="identifier">init</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&gt;())</span>
<span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"greet"</span><span class="special">,</span> <span class="special">&amp;</span><span class="identifier">World</span><span class="special">::</span><span class="identifier">greet</span><span class="special">)</span>
<span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"set"</span><span class="special">,</span> <span class="special">&amp;</span><span class="identifier">World</span><span class="special">::</span><span class="identifier">set</span><span class="special">)</span>
<span class="special">;</span>
<span class="special">}</span>
</pre>
<p><tt class="literal">init&lt;std::string&gt;()</tt> exposes the constructor taking
in a <tt class="literal">std::string</tt> (in Python, constructors are spelled
"<tt class="literal">"<span class="underline">_init</span>_"</tt>").
</p>
<p>
We can expose additional constructors by passing more <tt class="literal">init&lt;...&gt;</tt>s to
the <tt class="literal">def()</tt> member function. Say for example we have another World
constructor taking in two doubles:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">class_</span><span class="special">&lt;</span><span class="identifier">World</span><span class="special">&gt;(</span><span class="string">"World"</span><span class="special">,</span><span class="identifier"> init</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&gt;())</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">init</span><span class="special">&lt;</span><span class="keyword">double</span><span class="special">,</span><span class="keyword"> double</span><span class="special">&gt;())</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"greet"</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">World</span><span class="special">::</span><span class="identifier">greet</span><span class="special">)</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"set"</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">World</span><span class="special">::</span><span class="identifier">set</span><span class="special">)</span><span class="special">
;</span></tt></pre>
We can expose additional constructors by passing more <tt class="literal">init&lt;...&gt;</tt>s
to the <tt class="literal">def()</tt> member function. Say for example we have
another World constructor taking in two doubles:
</p>
<pre class="programlisting">
<span class="identifier">class_</span><span class="special">&lt;</span><span class="identifier">World</span><span class="special">&gt;(</span><span class="string">"World"</span><span class="special">,</span> <span class="identifier">init</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&gt;())</span>
<span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">init</span><span class="special">&lt;</span><span class="keyword">double</span><span class="special">,</span> <span class="keyword">double</span><span class="special">&gt;())</span>
<span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"greet"</span><span class="special">,</span> <span class="special">&amp;</span><span class="identifier">World</span><span class="special">::</span><span class="identifier">greet</span><span class="special">)</span>
<span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"set"</span><span class="special">,</span> <span class="special">&amp;</span><span class="identifier">World</span><span class="special">::</span><span class="identifier">set</span><span class="special">)</span>
<span class="special">;</span>
</pre>
<p>
On the other hand, if we do not wish to expose any constructors at
all, we may use <tt class="literal">no_init</tt> instead:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">class_</span><span class="special">&lt;</span><span class="identifier">Abstract</span><span class="special">&gt;(</span><span class="string">"Abstract"</span><span class="special">,</span><span class="identifier"> no_init</span><span class="special">)</span></tt></pre>
On the other hand, if we do not wish to expose any constructors at all, we
may use <tt class="literal">no_init</tt> instead:
</p>
<pre class="programlisting">
<span class="identifier">class_</span><span class="special">&lt;</span><span class="identifier">Abstract</span><span class="special">&gt;(</span><span class="string">"Abstract"</span><span class="special">,</span> <span class="identifier">no_init</span><span class="special">)</span>
</pre>
<p>
This actually adds an <tt class="literal"><span class="underline">_init</span>_</tt> method which always raises a
Python RuntimeError exception.</p>
This actually adds an <tt class="literal"><span class="underline">_init</span>_</tt>
method which always raises a Python RuntimeError exception.
</p>
</div>
<div class="section" lang="en">
<div class="titlepage"><div><div><h3 class="title">
<a name="python.class_data_members"></a>Class Data Members</h3></div></div></div>
<p>
Data members may also be exposed to Python so that they can be
accessed as attributes of the corresponding Python class. Each data
member that we wish to be exposed may be regarded as <span class="bold"><b>read-only</b></span> or
<span class="bold"><b>read-write</b></span>. Consider this class <tt class="literal">Var</tt>:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">struct</span><span class="identifier"> Var</span><span class="special">
{</span><span class="identifier">
Var</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="identifier"> name</span><span class="special">)</span><span class="special"> :</span><span class="identifier"> name</span><span class="special">(</span><span class="identifier">name</span><span class="special">),</span><span class="identifier"> value</span><span class="special">()</span><span class="special"> {}</span><span class="identifier">
std</span><span class="special">::</span><span class="identifier">string</span><span class="keyword"> const</span><span class="identifier"> name</span><span class="special">;</span><span class="keyword">
float</span><span class="identifier"> value</span><span class="special">;</span><span class="special">
};</span></tt></pre>
Class Data MembersData members may also be exposed to Python so that they
can be accessed as attributes of the corresponding Python class. Each data
member that we wish to be exposed may be regarded as <span class="bold"><b>read-only</b></span>
or <span class="bold"><b>read-write</b></span>. Consider this class <tt class="literal">Var</tt>:
</p>
<pre class="programlisting">
<span class="keyword">struct</span> <span class="identifier">Var</span>
<span class="special">{</span>
<span class="identifier">Var</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">name</span><span class="special">)</span> <span class="special">:</span> <span class="identifier">name</span><span class="special">(</span><span class="identifier">name</span><span class="special">),</span> <span class="identifier">value</span><span class="special">()</span> <span class="special">{}</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="keyword">const</span> <span class="identifier">name</span><span class="special">;</span>
<span class="keyword">float</span> <span class="identifier">value</span><span class="special">;</span>
<span class="special">};</span>
</pre>
<p>
Our C++ <tt class="literal">Var</tt> class and its data members can be exposed to Python:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">class_</span><span class="special">&lt;</span><span class="identifier">Var</span><span class="special">&gt;(</span><span class="string">"Var"</span><span class="special">,</span><span class="identifier"> init</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&gt;())</span><span class="special">
.</span><span class="identifier">def_readonly</span><span class="special">(</span><span class="string">"name"</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">Var</span><span class="special">::</span><span class="identifier">name</span><span class="special">)</span><span class="special">
.</span><span class="identifier">def_readwrite</span><span class="special">(</span><span class="string">"value"</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">Var</span><span class="special">::</span><span class="identifier">value</span><span class="special">);</span></tt></pre>
Our C++ <tt class="literal">Var</tt> class and its data members can be exposed
to Python:
</p>
<pre class="programlisting">
<span class="identifier">class_</span><span class="special">&lt;</span><span class="identifier">Var</span><span class="special">&gt;(</span><span class="string">"Var"</span><span class="special">,</span> <span class="identifier">init</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&gt;())</span>
<span class="special">.</span><span class="identifier">def_readonly</span><span class="special">(</span><span class="string">"name"</span><span class="special">,</span> <span class="special">&amp;</span><span class="identifier">Var</span><span class="special">::</span><span class="identifier">name</span><span class="special">)</span>
<span class="special">.</span><span class="identifier">def_readwrite</span><span class="special">(</span><span class="string">"value"</span><span class="special">,</span> <span class="special">&amp;</span><span class="identifier">Var</span><span class="special">::</span><span class="identifier">value</span><span class="special">);</span>
</pre>
<p>
Then, in Python, assuming we have placed our Var class inside the namespace
hello as we did before:</p>
Then, in Python, assuming we have placed our Var class inside the namespace
hello as we did before:
</p>
<p></p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="identifier"> x</span><span class="special"> =</span><span class="identifier"> hello</span><span class="special">.</span><span class="identifier">Var</span><span class="special">(</span><span class="string">'pi'</span><span class="special">)</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> x</span><span class="special">.</span><span class="identifier">value</span><span class="special"> =</span><span class="number"> 3.14</span><span class="special">
&gt;&gt;&gt;</span><span class="keyword"> print</span><span class="identifier"> x</span><span class="special">.</span><span class="identifier">name</span><span class="special">,</span><span class="string"> 'is around'</span><span class="special">,</span><span class="identifier"> x</span><span class="special">.</span><span class="identifier">value</span><span class="identifier">
pi</span><span class="keyword"> is</span><span class="identifier"> around</span><span class="number"> 3.14</span></tt></pre>
<pre class="programlisting">
<span class="special">&gt;&gt;&gt;</span> <span class="identifier">x</span> <span class="special">=</span> <span class="identifier">hello</span><span class="special">.</span><span class="identifier">Var</span><span class="special">(</span><span class="string">'pi'</span><span class="special">)</span>
<span class="special">&gt;&gt;&gt;</span> <span class="identifier">x</span><span class="special">.</span><span class="identifier">value</span> <span class="special">=</span> <span class="number">3.14</span>
<span class="special">&gt;&gt;&gt;</span> <span class="keyword">print</span> <span class="identifier">x</span><span class="special">.</span><span class="identifier">name</span><span class="special">,</span> <span class="string">'is around'</span><span class="special">,</span> <span class="identifier">x</span><span class="special">.</span><span class="identifier">value</span>
<span class="identifier">pi</span> <span class="keyword">is</span> <span class="identifier">around</span> <span class="number">3.14</span>
</pre>
<p>
Note that <tt class="literal">name</tt> is exposed as <span class="bold"><b>read-only</b></span> while <tt class="literal">value</tt> is exposed
as <span class="bold"><b>read-write</b></span>.</p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="identifier"> x</span><span class="special">.</span><span class="identifier">name</span><span class="special"> =</span><span class="string"> 'e'</span><span class="comment"> # can't change name
</span><span class="identifier">Traceback</span><span class="special"> (</span><span class="identifier">most</span><span class="identifier"> recent</span><span class="identifier"> call</span><span class="identifier"> last</span><span class="special">):</span><span class="identifier">
File</span><span class="string"> "&lt;stdin&gt;"</span><span class="special">,</span><span class="identifier"> line</span><span class="number"> 1</span><span class="special">,</span><span class="keyword"> in</span>#<span class="identifier">
AttributeError</span><span class="special">:</span><span class="identifier"> can</span>#<span class="identifier">t</span><span class="identifier"> set</span><span class="identifier"> attribute</span></tt></pre>
Note that <tt class="literal">name</tt> is exposed as <span class="bold"><b>read-only</b></span>
while <tt class="literal">value</tt> is exposed as <span class="bold"><b>read-write</b></span>.
</p>
<pre class="programlisting">
<span class="special">&gt;&gt;&gt;</span> <span class="identifier">x</span><span class="special">.</span><span class="identifier">name</span> <span class="special">=</span> <span class="string">'e'</span> <span class="comment"># can't change name
</span><span class="identifier">Traceback</span> <span class="special">(</span><span class="identifier">most</span> <span class="identifier">recent</span> <span class="identifier">call</span> <span class="identifier">last</span><span class="special">):</span>
<span class="identifier">File</span> <span class="string">"&lt;stdin&gt;"</span><span class="special">,</span> <span class="identifier">line</span> <span class="number">1</span><span class="special">,</span> <span class="keyword">in</span> #
<span class="identifier">AttributeError</span><span class="special">:</span> <span class="identifier">can</span>#<span class="identifier">t</span> <span class="identifier">set</span> <span class="identifier">attribute</span>
</pre>
</div>
<div class="section" lang="en">
<div class="titlepage"><div><div><h3 class="title">
<a name="python.class_properties"></a>Class Properties</h3></div></div></div>
<p>
In C++, classes with public data members are usually frowned
upon. Well designed classes that take advantage of encapsulation hide
the class' data members. The only way to access the class' data is
through access (getter/setter) functions. Access functions expose class
properties. Here's an example:</p>
Class PropertiesIn C++, classes with public data members are usually frowned
upon. Well designed classes that take advantage of encapsulation hide the
class' data members. The only way to access the class' data is through access
(getter/setter) functions. Access functions expose class properties. Here's
an example:
</p>
<p></p>
<pre class="programlisting"><tt class="literal"><span class="keyword">struct</span><span class="identifier"> Num</span><span class="special">
{</span><span class="identifier">
Num</span><span class="special">();</span><span class="keyword">
float</span><span class="identifier"> get</span><span class="special">()</span><span class="keyword"> const</span><span class="special">;</span><span class="keyword">
void</span><span class="identifier"> set</span><span class="special">(</span><span class="keyword">float</span><span class="identifier"> value</span><span class="special">);</span><span class="special">
...</span><span class="special">
};</span></tt></pre>
<pre class="programlisting">
<span class="keyword">struct</span> <span class="identifier">Num</span>
<span class="special">{</span>
<span class="identifier">Num</span><span class="special">();</span>
<span class="keyword">float</span> <span class="identifier">get</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span>
<span class="keyword">void</span> <span class="identifier">set</span><span class="special">(</span><span class="keyword">float</span> <span class="identifier">value</span><span class="special">);</span>
<span class="special">...</span>
<span class="special">};</span>
</pre>
<p>
However, in Python attribute access is fine; it doesn't neccessarily break
encapsulation to let users handle attributes directly, because the
attributes can just be a different syntax for a method call. Wrapping our
<tt class="literal">Num</tt> class using Boost.Python:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">class_</span><span class="special">&lt;</span><span class="identifier">Num</span><span class="special">&gt;(</span><span class="string">"Num"</span><span class="special">)</span><span class="special">
.</span><span class="identifier">add_property</span><span class="special">(</span><span class="string">"rovalue"</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">Num</span><span class="special">::</span><span class="identifier">get</span><span class="special">)</span><span class="special">
.</span><span class="identifier">add_property</span><span class="special">(</span><span class="string">"value"</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">Num</span><span class="special">::</span><span class="identifier">get</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">Num</span><span class="special">::</span><span class="identifier">set</span><span class="special">);</span></tt></pre>
However, in Python attribute access is fine; it doesn't neccessarily break
encapsulation to let users handle attributes directly, because the attributes
can just be a different syntax for a method call. Wrapping our <tt class="literal">Num</tt>
class using Boost.Python:
</p>
<pre class="programlisting">
<span class="identifier">class_</span><span class="special">&lt;</span><span class="identifier">Num</span><span class="special">&gt;(</span><span class="string">"Num"</span><span class="special">)</span>
<span class="special">.</span><span class="identifier">add_property</span><span class="special">(</span><span class="string">"rovalue"</span><span class="special">,</span> <span class="special">&amp;</span><span class="identifier">Num</span><span class="special">::</span><span class="identifier">get</span><span class="special">)</span>
<span class="special">.</span><span class="identifier">add_property</span><span class="special">(</span><span class="string">"value"</span><span class="special">,</span> <span class="special">&amp;</span><span class="identifier">Num</span><span class="special">::</span><span class="identifier">get</span><span class="special">,</span> <span class="special">&amp;</span><span class="identifier">Num</span><span class="special">::</span><span class="identifier">set</span><span class="special">);</span>
</pre>
<p>
And at last, in Python:</p>
And at last, in Python:
</p>
<p></p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="identifier"> x</span><span class="special"> =</span><span class="identifier"> Num</span><span class="special">()</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> x</span><span class="special">.</span><span class="identifier">value</span><span class="special"> =</span><span class="number"> 3.14</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> x</span><span class="special">.</span><span class="identifier">value</span><span class="special">,</span><span class="identifier"> x</span><span class="special">.</span><span class="identifier">rovalue</span><span class="special">
(</span><span class="number">3.14</span><span class="special">,</span><span class="number"> 3.14</span><span class="special">)</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> x</span><span class="special">.</span><span class="identifier">rovalue</span><span class="special"> =</span><span class="number"> 2.17</span><span class="comment"> # error!
</span></tt></pre>
<pre class="programlisting">
<span class="special">&gt;&gt;&gt;</span> <span class="identifier">x</span> <span class="special">=</span> <span class="identifier">Num</span><span class="special">()</span>
<span class="special">&gt;&gt;&gt;</span> <span class="identifier">x</span><span class="special">.</span><span class="identifier">value</span> <span class="special">=</span> <span class="number">3.14</span>
<span class="special">&gt;&gt;&gt;</span> <span class="identifier">x</span><span class="special">.</span><span class="identifier">value</span><span class="special">,</span> <span class="identifier">x</span><span class="special">.</span><span class="identifier">rovalue</span>
<span class="special">(</span><span class="number">3.14</span><span class="special">,</span> <span class="number">3.14</span><span class="special">)</span>
<span class="special">&gt;&gt;&gt;</span> <span class="identifier">x</span><span class="special">.</span><span class="identifier">rovalue</span> <span class="special">=</span> <span class="number">2.17</span> <span class="comment"># error!
</span></pre>
<p>
Take note that the class property <tt class="literal">rovalue</tt> is exposed as <span class="bold"><b>read-only</b></span>
since the <tt class="literal">rovalue</tt> setter member function is not passed in:</p>
Take note that the class property <tt class="literal">rovalue</tt> is exposed as
<span class="bold"><b>read-only</b></span> since the <tt class="literal">rovalue</tt>
setter member function is not passed in:
</p>
<p></p>
<pre class="programlisting"><tt class="literal"><span class="special">.</span><span class="identifier">add_property</span><span class="special">(</span><span class="string">"rovalue"</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">Num</span><span class="special">::</span><span class="identifier">get</span><span class="special">)</span></tt></pre>
<pre class="programlisting">
<span class="special">.</span><span class="identifier">add_property</span><span class="special">(</span><span class="string">"rovalue"</span><span class="special">,</span> <span class="special">&amp;</span><span class="identifier">Num</span><span class="special">::</span><span class="identifier">get</span><span class="special">)</span>
</pre>
</div>
<div class="section" lang="en">
<div class="titlepage"><div><div><h3 class="title">
<a name="python.inheritance"></a>Inheritance</h3></div></div></div>
<p>
In the previous examples, we dealt with classes that are not polymorphic.
This is not often the case. Much of the time, we will be wrapping
polymorphic classes and class hierarchies related by inheritance. We will
often have to write Boost.Python wrappers for classes that are derived from
abstract base classes.</p>
InheritanceIn the previous examples, we dealt with classes that are not polymorphic.
This is not often the case. Much of the time, we will be wrapping polymorphic
classes and class hierarchies related by inheritance. We will often have
to write Boost.Python wrappers for classes that are derived from abstract
base classes.
</p>
<p>
Consider this trivial inheritance structure:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">struct</span><span class="identifier"> Base</span><span class="special"> {</span><span class="keyword"> virtual</span><span class="special"> ~</span><span class="identifier">Base</span><span class="special">();</span><span class="special"> };</span><span class="keyword">
struct</span><span class="identifier"> Derived</span><span class="special"> :</span><span class="identifier"> Base</span><span class="special"> {};</span></tt></pre>
Consider this trivial inheritance structure:
</p>
<pre class="programlisting">
<span class="keyword">struct</span> <span class="identifier">Base</span> <span class="special">{</span> <span class="keyword">virtual</span> <span class="special">~</span><span class="identifier">Base</span><span class="special">();</span> <span class="special">};</span>
<span class="keyword">struct</span> <span class="identifier">Derived</span> <span class="special">:</span> <span class="identifier">Base</span> <span class="special">{};</span>
</pre>
<p>
And a set of C++ functions operating on <tt class="literal">Base</tt> and <tt class="literal">Derived</tt> object
instances:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">void</span><span class="identifier"> b</span><span class="special">(</span><span class="identifier">Base</span><span class="special">*);</span><span class="keyword">
void</span><span class="identifier"> d</span><span class="special">(</span><span class="identifier">Derived</span><span class="special">*);</span><span class="identifier">
Base</span><span class="special">*</span><span class="identifier"> factory</span><span class="special">()</span><span class="special"> {</span><span class="keyword"> return</span><span class="keyword"> new</span><span class="identifier"> Derived</span><span class="special">;</span><span class="special"> }</span></tt></pre>
And a set of C++ functions operating on <tt class="literal">Base</tt> and <tt class="literal">Derived</tt>
object instances:
</p>
<pre class="programlisting">
<span class="keyword">void</span> <span class="identifier">b</span><span class="special">(</span><span class="identifier">Base</span><span class="special">*);</span>
<span class="keyword">void</span> <span class="identifier">d</span><span class="special">(</span><span class="identifier">Derived</span><span class="special">*);</span>
<span class="identifier">Base</span><span class="special">*</span> <span class="identifier">factory</span><span class="special">()</span> <span class="special">{</span> <span class="keyword">return</span> <span class="keyword">new</span> <span class="identifier">Derived</span><span class="special">;</span> <span class="special">}</span>
</pre>
<p>
We've seen how we can wrap the base class <tt class="literal">Base</tt>:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">class_</span><span class="special">&lt;</span><span class="identifier">Base</span><span class="special">&gt;(</span><span class="string">"Base"</span><span class="special">)</span><span class="comment">
/*...*/</span><span class="special">
;</span></tt></pre>
We've seen how we can wrap the base class <tt class="literal">Base</tt>:
</p>
<pre class="programlisting">
<span class="identifier">class_</span><span class="special">&lt;</span><span class="identifier">Base</span><span class="special">&gt;(</span><span class="string">"Base"</span><span class="special">)</span>
<span class="comment">/*...*/</span>
<span class="special">;</span>
</pre>
<p>
Now we can inform Boost.Python of the inheritance relationship between
<tt class="literal">Derived</tt> and its base class <tt class="literal">Base</tt>. Thus:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">class_</span><span class="special">&lt;</span><span class="identifier">Derived</span><span class="special">,</span><span class="identifier"> bases</span><span class="special">&lt;</span><span class="identifier">Base</span><span class="special">&gt;</span><span class="special"> &gt;(</span><span class="string">"Derived"</span><span class="special">)</span><span class="comment">
/*...*/</span><span class="special">
;</span></tt></pre>
Now we can inform Boost.Python of the inheritance relationship between <tt class="literal">Derived</tt>
and its base class <tt class="literal">Base</tt>. Thus:
</p>
<pre class="programlisting">
<span class="identifier">class_</span><span class="special">&lt;</span><span class="identifier">Derived</span><span class="special">,</span> <span class="identifier">bases</span><span class="special">&lt;</span><span class="identifier">Base</span><span class="special">&gt;</span> <span class="special">&gt;(</span><span class="string">"Derived"</span><span class="special">)</span>
<span class="comment">/*...*/</span>
<span class="special">;</span>
</pre>
<p>
Doing so, we get some things for free:</p>
Doing so, we get some things for free:
</p>
<div class="orderedlist"><ol type="1">
<li>
Derived automatically inherits all of Base's Python methods
(wrapped C++ member functions)
</li>
Derived automatically inherits all of Base's Python methods (wrapped C++
member functions)
</li>
<li>
<span class="bold"><b>If</b></span> Base is polymorphic, <tt class="literal">Derived</tt> objects which have been passed to
Python via a pointer or reference to <tt class="literal">Base</tt> can be passed where a pointer
or reference to <tt class="literal">Derived</tt> is expected.
</li>
<span class="bold"><b>If</b></span> Base is polymorphic, <tt class="literal">Derived</tt>
objects which have been passed to Python via a pointer or reference to
<tt class="literal">Base</tt> can be passed where a pointer or reference to
<tt class="literal">Derived</tt> is expected.
</li>
</ol></div>
<p>
Now, we shall expose the C++ free functions <tt class="literal">b</tt> and <tt class="literal">d</tt> and <tt class="literal">factory</tt>:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">def</span><span class="special">(</span><span class="string">"b"</span><span class="special">,</span><span class="identifier"> b</span><span class="special">);</span><span class="identifier">
def</span><span class="special">(</span><span class="string">"d"</span><span class="special">,</span><span class="identifier"> d</span><span class="special">);</span><span class="identifier">
def</span><span class="special">(</span><span class="string">"factory"</span><span class="special">,</span><span class="identifier"> factory</span><span class="special">);</span></tt></pre>
Now, we shall expose the C++ free functions <tt class="literal">b</tt> and <tt class="literal">d</tt>
and <tt class="literal">factory</tt>:
</p>
<pre class="programlisting">
<span class="identifier">def</span><span class="special">(</span><span class="string">"b"</span><span class="special">,</span> <span class="identifier">b</span><span class="special">);</span>
<span class="identifier">def</span><span class="special">(</span><span class="string">"d"</span><span class="special">,</span> <span class="identifier">d</span><span class="special">);</span>
<span class="identifier">def</span><span class="special">(</span><span class="string">"factory"</span><span class="special">,</span> <span class="identifier">factory</span><span class="special">);</span>
</pre>
<p>
Note that free function <tt class="literal">factory</tt> is being used to generate new
instances of class <tt class="literal">Derived</tt>. In such cases, we use
<tt class="literal">return_value_policy&lt;manage_new_object&gt;</tt> to instruct Python to adopt
the pointer to <tt class="literal">Base</tt> and hold the instance in a new Python <tt class="literal">Base</tt>
object until the the Python object is destroyed. We shall see more of
Boost.Python <a href="functions.html#python.call_policies" title="Call Policies">call policies</a> later.</p>
<pre class="programlisting"><tt class="literal"><span class="comment">// Tell Python to take ownership of factory's result
</span><span class="identifier">def</span><span class="special">(</span><span class="string">"factory"</span><span class="special">,</span><span class="identifier"> factory</span><span class="special">,</span><span class="identifier">
return_value_policy</span><span class="special">&lt;</span><span class="identifier">manage_new_object</span><span class="special">&gt;());</span></tt></pre>
Note that free function <tt class="literal">factory</tt> is being used to generate
new instances of class <tt class="literal">Derived</tt>. In such cases, we use
<tt class="literal">return_value_policy&lt;manage_new_object&gt;</tt> to instruct
Python to adopt the pointer to <tt class="literal">Base</tt> and hold the instance
in a new Python <tt class="literal">Base</tt> object until the the Python object
is destroyed. We shall see more of Boost.Python <a href="functions.html#python.call_policies" title="Call Policies">call
policies</a> later.
</p>
<pre class="programlisting">
<span class="comment">// Tell Python to take ownership of factory's result
</span><span class="identifier">def</span><span class="special">(</span><span class="string">"factory"</span><span class="special">,</span> <span class="identifier">factory</span><span class="special">,</span>
<span class="identifier">return_value_policy</span><span class="special">&lt;</span><span class="identifier">manage_new_object</span><span class="special">&gt;());</span>
</pre>
</div>
<div class="section" lang="en">
<div class="titlepage"><div><div><h3 class="title">
<a name="python.class_virtual_functions"></a>Class Virtual Functions</h3></div></div></div>
<p>
In this section, we shall learn how to make functions behave polymorphically
through virtual functions. Continuing our example, let us add a virtual function
to our <tt class="literal">Base</tt> class:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">struct</span><span class="identifier"> Base</span><span class="special">
{</span><span class="keyword">
virtual</span><span class="special"> ~</span><span class="identifier">Base</span><span class="special">()</span><span class="special"> {}</span><span class="keyword">
virtual</span><span class="keyword"> int</span><span class="identifier"> f</span><span class="special">()</span><span class="special"> =</span><span class="number"> 0</span><span class="special">;</span><span class="special">
};</span></tt></pre>
Class Virtual FunctionsIn this section, we shall learn how to make functions
behave polymorphically through virtual functions. Continuing our example,
let us add a virtual function to our <tt class="literal">Base</tt> class:
</p>
<pre class="programlisting">
<span class="keyword">struct</span> <span class="identifier">Base</span>
<span class="special">{</span>
<span class="keyword">virtual</span> <span class="special">~</span><span class="identifier">Base</span><span class="special">()</span> <span class="special">{}</span>
<span class="keyword">virtual</span> <span class="keyword">int</span> <span class="identifier">f</span><span class="special">()</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span>
<span class="special">};</span>
</pre>
<p>
One of the goals of Boost.Python is to be minimally intrusive on an existing C++
design. In principle, it should be possible to expose the interface for a 3rd
party library without changing it. It is not ideal to add anything to our class
<tt class="computeroutput"><span class="identifier">Base</span></tt>. Yet, when you have a virtual function that's going to be overridden in
Python and called polymorphically <span class="bold"><b>from C++</b></span>, we'll need to add some
scaffoldings to make things work properly. What we'll do is write a class
wrapper that derives from <tt class="computeroutput"><span class="identifier">Base</span></tt> that will unintrusively hook into the virtual
functions so that a Python override may be called:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">struct</span><span class="identifier"> BaseWrap</span><span class="special"> :</span><span class="identifier"> Base</span><span class="special">,</span><span class="identifier"> wrapper</span><span class="special">&lt;</span><span class="identifier">Base</span><span class="special">&gt;</span><span class="special">
{</span><span class="keyword">
int</span><span class="identifier"> f</span><span class="special">()</span><span class="special">
{</span><span class="keyword">
return</span><span class="keyword"> this</span><span class="special">-&gt;</span><span class="identifier">get_override</span><span class="special">(</span><span class="string">"f"</span><span class="special">)();</span><span class="special">
}</span><span class="special">
};</span></tt></pre>
One of the goals of Boost.Python is to be minimally intrusive on an existing
C++ design. In principle, it should be possible to expose the interface for
a 3rd party library without changing it. It is not ideal to add anything
to our class <tt class="computeroutput"><span class="identifier">Base</span></tt>. Yet, when
you have a virtual function that's going to be overridden in Python and called
polymorphically <span class="bold"><b>from C++</b></span>, we'll need to
add some scaffoldings to make things work properly. What we'll do is write
a class wrapper that derives from <tt class="computeroutput"><span class="identifier">Base</span></tt>
that will unintrusively hook into the virtual functions so that a Python
override may be called:
</p>
<pre class="programlisting">
<span class="keyword">struct</span> <span class="identifier">BaseWrap</span> <span class="special">:</span> <span class="identifier">Base</span><span class="special">,</span> <span class="identifier">wrapper</span><span class="special">&lt;</span><span class="identifier">Base</span><span class="special">&gt;</span>
<span class="special">{</span>
<span class="keyword">int</span> <span class="identifier">f</span><span class="special">()</span>
<span class="special">{</span>
<span class="keyword">return</span> <span class="keyword">this</span><span class="special">-&gt;</span><span class="identifier">get_override</span><span class="special">(</span><span class="string">"f"</span><span class="special">)();</span>
<span class="special">}</span>
<span class="special">};</span>
</pre>
<p>
Notice too that in addition to inheriting from <tt class="computeroutput"><span class="identifier">Base</span></tt>, we also multiply-
inherited <tt class="computeroutput"><span class="identifier">wrapper</span><span class="special">&lt;</span><span class="identifier">Base</span><span class="special">&gt;</span></tt> (See <a href="../../../../v2/wrapper.html" target="_top">Wrapper</a>). The
<tt class="computeroutput"><span class="identifier">wrapper</span></tt> template makes the job of wrapping classes that are meant to
overridden in Python, easier.</p>
Notice too that in addition to inheriting from <tt class="computeroutput"><span class="identifier">Base</span></tt>,
we also multiply- inherited <tt class="computeroutput"><span class="identifier">wrapper</span><span class="special">&lt;</span><span class="identifier">Base</span><span class="special">&gt;</span></tt> (See <a href="../../../../v2/wrapper.html" target="_top">Wrapper</a>).
The <tt class="computeroutput"><span class="identifier">wrapper</span></tt> template makes
the job of wrapping classes that are meant to overridden in Python, easier.
</p>
<div class="informaltable"><table class="table">
<colgroup><col></colgroup>
<tbody><tr><td class="blurb">
<span class="inlinemediaobject"><img src="../images/alert.png"></span><span class="bold"><b>MSVC6/7 Workaround</b></span><br><br>
If you are using Microsoft Visual C++ 6 or 7, you have to write <tt class="computeroutput"><span class="identifier">f</span></tt> as:<br><br><tt class="computeroutput"><span class="keyword">return</span><span class="identifier"> call</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;(</span><span class="keyword">this</span><span class="special">-&gt;</span><span class="identifier">get_override</span><span class="special">(</span><span class="string">"f"</span><span class="special">).</span><span class="identifier">ptr</span><span class="special">());</span></tt>.</td></tr></tbody>
<span class="inlinemediaobject"><img src="../images/alert.png"></span> <span class="bold"><b>MSVC6/7 Workaround</b></span><br><br> If you are using
Microsoft Visual C++ 6 or 7, you have to write <tt class="computeroutput"><span class="identifier">f</span></tt>
as:<br><br><tt class="computeroutput"><span class="keyword">return</span> <span class="identifier">call</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;(</span><span class="keyword">this</span><span class="special">-&gt;</span><span class="identifier">get_override</span><span class="special">(</span><span class="string">"f"</span><span class="special">).</span><span class="identifier">ptr</span><span class="special">());</span></tt>.</td></tr></tbody>
</table></div>
<p>
BaseWrap's overridden virtual member function <tt class="computeroutput"><span class="identifier">f</span></tt> in effect calls the
corresponding method of the Python object through <tt class="computeroutput"><span class="identifier">get_override</span></tt>.</p>
BaseWrap's overridden virtual member function <tt class="computeroutput"><span class="identifier">f</span></tt>
in effect calls the corresponding method of the Python object through <tt class="computeroutput"><span class="identifier">get_override</span></tt>.
</p>
<p>
Finally, exposing <tt class="computeroutput"><span class="identifier">Base</span></tt>:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">class_</span><span class="special">&lt;</span><span class="identifier">BaseWrap</span><span class="special">,</span><span class="identifier"> boost</span><span class="special">::</span><span class="identifier">noncopyable</span><span class="special">&gt;(</span><span class="string">"Base"</span><span class="special">)</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span><span class="identifier"> pure_virtual</span><span class="special">(&amp;</span><span class="identifier">Base</span><span class="special">::</span><span class="identifier">f</span><span class="special">))</span><span class="special">
;</span></tt></pre>
<p><tt class="computeroutput"><span class="identifier">pure_virtual</span></tt> signals Boost.Python that the function <tt class="computeroutput"><span class="identifier">f</span></tt> is a pure virtual
function.</p>
Finally, exposing <tt class="computeroutput"><span class="identifier">Base</span></tt>:
</p>
<pre class="programlisting">
<span class="identifier">class_</span><span class="special">&lt;</span><span class="identifier">BaseWrap</span><span class="special">,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">noncopyable</span><span class="special">&gt;(</span><span class="string">"Base"</span><span class="special">)</span>
<span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span> <span class="identifier">pure_virtual</span><span class="special">(&amp;</span><span class="identifier">Base</span><span class="special">::</span><span class="identifier">f</span><span class="special">))</span>
<span class="special">;</span>
</pre>
<p><tt class="computeroutput"><span class="identifier">pure_virtual</span></tt> signals Boost.Python
that the function <tt class="computeroutput"><span class="identifier">f</span></tt> is a
pure virtual function.
</p>
<div class="informaltable"><table class="table">
<colgroup><col></colgroup>
<tbody><tr><td class="blurb">
<span class="inlinemediaobject"><img src="../images/note.png"></span><span class="bold"><b>member function and methods</b></span><br><br>
Python, like
many object oriented languages uses the term <span class="bold"><b>methods</b></span>. Methods
correspond roughly to C++'s <span class="bold"><b>member functions</b></span>
<span class="inlinemediaobject"><img src="../images/note.png"></span> <span class="bold"><b>member function and methods</b></span><br><br> Python,
like many object oriented languages uses the term <span class="bold"><b>methods</b></span>.
Methods correspond roughly to C++'s <span class="bold"><b>member functions</b></span>
</td></tr></tbody>
</table></div>
</div>
@ -320,153 +409,196 @@ correspond roughly to C++'s <span class="bold"><b>member functions</b></span>
<div class="titlepage"><div><div><h3 class="title">
<a name="python.virtual_functions_with_default_implementations"></a>Virtual Functions with Default Implementations</h3></div></div></div>
<p>
We've seen in the previous section how classes with pure virtual functions are
wrapped using Boost.Python's <a href="../../../../v2/wrapper.html" target="_top">class wrapper</a>
facilities. If we wish to wrap <span class="bold"><b>non</b></span>-pure-virtual functions instead, the
mechanism is a bit different.</p>
Virtual Functions with Default ImplementationsWe've seen in the previous
section how classes with pure virtual functions are wrapped using Boost.Python's
<a href="../../../../v2/wrapper.html" target="_top">class wrapper</a> facilities. If
we wish to wrap <span class="bold"><b>non</b></span>-pure-virtual functions
instead, the mechanism is a bit different.
</p>
<p>
Recall that in the <a href="exposing.html#python.class_virtual_functions" title="Class Virtual Functions">previous section</a>, we
wrapped a class with a pure virtual function that we then implemented in C++, or
Python classes derived from it. Our base class:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">struct</span><span class="identifier"> Base</span><span class="special">
{</span><span class="keyword">
virtual</span><span class="keyword"> int</span><span class="identifier"> f</span><span class="special">()</span><span class="special"> =</span><span class="number"> 0</span><span class="special">;</span><span class="special">
};</span></tt></pre>
Recall that in the <a href="exposing.html#python.class_virtual_functions" title="Class Virtual Functions">previous
section</a>, we wrapped a class with a pure virtual function that we then
implemented in C++, or Python classes derived from it. Our base class:
</p>
<pre class="programlisting">
<span class="keyword">struct</span> <span class="identifier">Base</span>
<span class="special">{</span>
<span class="keyword">virtual</span> <span class="keyword">int</span> <span class="identifier">f</span><span class="special">()</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span>
<span class="special">};</span>
</pre>
<p>
had a pure virtual function <tt class="literal">f</tt>. If, however, its member function <tt class="literal">f</tt> was
not declared as pure virtual:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">struct</span><span class="identifier"> Base</span><span class="special">
{</span><span class="keyword">
virtual</span><span class="special"> ~</span><span class="identifier">Base</span><span class="special">()</span><span class="special"> {}</span><span class="keyword">
virtual</span><span class="keyword"> int</span><span class="identifier"> f</span><span class="special">()</span><span class="special"> {</span><span class="keyword"> return</span><span class="number"> 0</span><span class="special">;</span><span class="special"> }</span><span class="special">
};</span></tt></pre>
had a pure virtual function <tt class="literal">f</tt>. If, however, its member
function <tt class="literal">f</tt> was not declared as pure virtual:
</p>
<pre class="programlisting">
<span class="keyword">struct</span> <span class="identifier">Base</span>
<span class="special">{</span>
<span class="keyword">virtual</span> <span class="special">~</span><span class="identifier">Base</span><span class="special">()</span> <span class="special">{}</span>
<span class="keyword">virtual</span> <span class="keyword">int</span> <span class="identifier">f</span><span class="special">()</span> <span class="special">{</span> <span class="keyword">return</span> <span class="number">0</span><span class="special">;</span> <span class="special">}</span>
<span class="special">};</span>
</pre>
<p>
We wrap it this way:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">struct</span><span class="identifier"> BaseWrap</span><span class="special"> :</span><span class="identifier"> Base</span><span class="special">,</span><span class="identifier"> wrapper</span><span class="special">&lt;</span><span class="identifier">Base</span><span class="special">&gt;</span><span class="special">
{</span><span class="keyword">
int</span><span class="identifier"> f</span><span class="special">()</span><span class="special">
{</span><span class="keyword">
if</span><span class="special"> (</span><span class="identifier">override</span><span class="identifier"> f</span><span class="special"> =</span><span class="keyword"> this</span><span class="special">-&gt;</span><span class="identifier">get_override</span><span class="special">(</span><span class="string">"f"</span><span class="special">))</span><span class="keyword">
return</span><span class="identifier"> f</span><span class="special">();</span><span class="comment"> // *note*
</span><span class="keyword"> return</span><span class="identifier"> Base</span><span class="special">::</span><span class="identifier">f</span><span class="special">();</span><span class="special">
}</span><span class="keyword">
We wrap it this way:
</p>
<pre class="programlisting">
<span class="keyword">struct</span> <span class="identifier">BaseWrap</span> <span class="special">:</span> <span class="identifier">Base</span><span class="special">,</span> <span class="identifier">wrapper</span><span class="special">&lt;</span><span class="identifier">Base</span><span class="special">&gt;</span>
<span class="special">{</span>
<span class="keyword">int</span> <span class="identifier">f</span><span class="special">()</span>
<span class="special">{</span>
<span class="keyword">if</span> <span class="special">(</span><span class="identifier">override</span> <span class="identifier">f</span> <span class="special">=</span> <span class="keyword">this</span><span class="special">-&gt;</span><span class="identifier">get_override</span><span class="special">(</span><span class="string">"f"</span><span class="special">))</span>
<span class="keyword">return</span> <span class="identifier">f</span><span class="special">();</span> <span class="comment">// *note*
</span> <span class="keyword">return</span> <span class="identifier">Base</span><span class="special">::</span><span class="identifier">f</span><span class="special">();</span>
<span class="special">}</span>
int</span><span class="identifier"> default_f</span><span class="special">()</span><span class="special"> {</span><span class="keyword"> return</span><span class="keyword"> this</span><span class="special">-&gt;</span><span class="identifier">Base</span><span class="special">::</span><span class="identifier">f</span><span class="special">();</span><span class="special"> }</span><span class="special">
};</span></tt></pre>
<span class="keyword">int</span> <span class="identifier">default_f</span><span class="special">()</span> <span class="special">{</span> <span class="keyword">return</span> <span class="keyword">this</span><span class="special">-&gt;</span><span class="identifier">Base</span><span class="special">::</span><span class="identifier">f</span><span class="special">();</span> <span class="special">}</span>
<span class="special">};</span>
</pre>
<p>
Notice how we implemented <tt class="computeroutput"><span class="identifier">BaseWrap</span><span class="special">::</span><span class="identifier">f</span></tt>. Now, we have to check if there is an
override for <tt class="computeroutput"><span class="identifier">f</span></tt>. If none, then we call <tt class="computeroutput"><span class="identifier">Base</span><span class="special">::</span><span class="identifier">f</span><span class="special">()</span></tt>.</p>
Notice how we implemented <tt class="computeroutput"><span class="identifier">BaseWrap</span><span class="special">::</span><span class="identifier">f</span></tt>. Now,
we have to check if there is an override for <tt class="computeroutput"><span class="identifier">f</span></tt>.
If none, then we call <tt class="computeroutput"><span class="identifier">Base</span><span class="special">::</span><span class="identifier">f</span><span class="special">()</span></tt>.
</p>
<div class="informaltable"><table class="table">
<colgroup><col></colgroup>
<tbody><tr><td class="blurb">
<span class="inlinemediaobject"><img src="../images/alert.png"></span><span class="bold"><b>MSVC6/7 Workaround</b></span><br><br>
If you are using Microsoft Visual C++ 6 or 7, you have to rewrite the line
with the <tt class="computeroutput"><span class="special">*</span><span class="identifier">note</span><span class="special">*</span></tt> as:<br><br><tt class="computeroutput"><span class="keyword">return</span><span class="identifier"> call</span><span class="special">&lt;</span><span class="keyword">char</span><span class="keyword"> const</span><span class="special">*&gt;(</span><span class="identifier">f</span><span class="special">.</span><span class="identifier">ptr</span><span class="special">());</span></tt>.</td></tr></tbody>
<span class="inlinemediaobject"><img src="../images/alert.png"></span> <span class="bold"><b>MSVC6/7 Workaround</b></span><br><br> If you are using
Microsoft Visual C++ 6 or 7, you have to rewrite the line with the
<tt class="computeroutput"><span class="special">*</span><span class="identifier">note</span><span class="special">*</span></tt> as:<br><br><tt class="computeroutput"><span class="keyword">return</span> <span class="identifier">call</span><span class="special">&lt;</span><span class="keyword">char</span> <span class="keyword">const</span><span class="special">*&gt;(</span><span class="identifier">f</span><span class="special">.</span><span class="identifier">ptr</span><span class="special">());</span></tt>.</td></tr></tbody>
</table></div>
<p>
Finally, exposing:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">class_</span><span class="special">&lt;</span><span class="identifier">BaseWrap</span><span class="special">,</span><span class="identifier"> boost</span><span class="special">::</span><span class="identifier">noncopyable</span><span class="special">&gt;(</span><span class="string">"Base"</span><span class="special">)</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">Base</span><span class="special">::</span><span class="identifier">f</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">BaseWrap</span><span class="special">::</span><span class="identifier">default_f</span><span class="special">)</span><span class="special">
;</span></tt></pre>
Finally, exposing:
</p>
<pre class="programlisting">
<span class="identifier">class_</span><span class="special">&lt;</span><span class="identifier">BaseWrap</span><span class="special">,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">noncopyable</span><span class="special">&gt;(</span><span class="string">"Base"</span><span class="special">)</span>
<span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span> <span class="special">&amp;</span><span class="identifier">Base</span><span class="special">::</span><span class="identifier">f</span><span class="special">,</span> <span class="special">&amp;</span><span class="identifier">BaseWrap</span><span class="special">::</span><span class="identifier">default_f</span><span class="special">)</span>
<span class="special">;</span>
</pre>
<p>
Take note that we expose both <tt class="computeroutput"><span class="special">&amp;</span><span class="identifier">Base</span><span class="special">::</span><span class="identifier">f</span></tt> and <tt class="computeroutput"><span class="special">&amp;</span><span class="identifier">BaseWrap</span><span class="special">::</span><span class="identifier">default_f</span></tt>.
Boost.Python needs to keep track of 1) the dispatch function <tt class="literal">f</tt> and 2) the
forwarding function to its default implementation <tt class="literal">default_f</tt>. There's a
special <tt class="literal">def</tt> function for this purpose.</p>
Take note that we expose both <tt class="computeroutput"><span class="special">&amp;</span><span class="identifier">Base</span><span class="special">::</span><span class="identifier">f</span></tt> and <tt class="computeroutput"><span class="special">&amp;</span><span class="identifier">BaseWrap</span><span class="special">::</span><span class="identifier">default_f</span></tt>. Boost.Python needs to keep track
of 1) the dispatch function <tt class="literal">f</tt> and 2) the forwarding function
to its default implementation <tt class="literal">default_f</tt>. There's a special
<tt class="literal">def</tt> function for this purpose.
</p>
<p>
In Python, the results would be as expected:</p>
In Python, the results would be as expected:
</p>
<p></p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="identifier"> base</span><span class="special"> =</span><span class="identifier"> Base</span><span class="special">()</span><span class="special">
&gt;&gt;&gt;</span><span class="keyword"> class</span><span class="identifier"> Derived</span><span class="special">(</span><span class="identifier">Base</span><span class="special">):</span><span class="special">
...</span><span class="keyword"> def</span><span class="identifier"> f</span><span class="special">(</span><span class="identifier">self</span><span class="special">):</span><span class="special">
...</span><span class="keyword"> return</span><span class="number"> 42</span><span class="special">
...</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> derived</span><span class="special"> =</span><span class="identifier"> Derived</span><span class="special">()</span></tt></pre>
<pre class="programlisting">
<span class="special">&gt;&gt;&gt;</span> <span class="identifier">base</span> <span class="special">=</span> <span class="identifier">Base</span><span class="special">()</span>
<span class="special">&gt;&gt;&gt;</span> <span class="keyword">class</span> <span class="identifier">Derived</span><span class="special">(</span><span class="identifier">Base</span><span class="special">):</span>
<span class="special">...</span> <span class="keyword">def</span> <span class="identifier">f</span><span class="special">(</span><span class="identifier">self</span><span class="special">):</span>
<span class="special">...</span> <span class="keyword">return</span> <span class="number">42</span>
<span class="special">...</span>
<span class="special">&gt;&gt;&gt;</span> <span class="identifier">derived</span> <span class="special">=</span> <span class="identifier">Derived</span><span class="special">()</span>
</pre>
<p>
Calling <tt class="literal">base.f()</tt>:</p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="identifier"> base</span><span class="special">.</span><span class="identifier">f</span><span class="special">()</span><span class="number">
0</span></tt></pre>
Calling <tt class="literal">base.f()</tt>:
</p>
<pre class="programlisting">
<span class="special">&gt;&gt;&gt;</span> <span class="identifier">base</span><span class="special">.</span><span class="identifier">f</span><span class="special">()</span>
<span class="number">0</span>
</pre>
<p>
Calling <tt class="literal">derived.f()</tt>:</p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="identifier"> derived</span><span class="special">.</span><span class="identifier">f</span><span class="special">()</span><span class="number">
42</span></tt></pre>
Calling <tt class="literal">derived.f()</tt>:
</p>
<pre class="programlisting">
<span class="special">&gt;&gt;&gt;</span> <span class="identifier">derived</span><span class="special">.</span><span class="identifier">f</span><span class="special">()</span>
<span class="number">42</span>
</pre>
</div>
<div class="section" lang="en">
<div class="titlepage"><div><div><h3 class="title">
<a name="python.class_operators_special_functions"></a>Class Operators/Special Functions</h3></div></div></div>
<a name="class_operators_special_functions.python_operators"></a><h2>
<a name="id447543"></a>Python Operators</h2>
<a name="class_operators_special_functions.class_operators_special_functionspython_operators"></a><h2>
<a name="id447955"></a>
Class Operators/Special FunctionsPython Operators
</h2>
<p>
C is well known for the abundance of operators. C++ extends this to the
extremes by allowing operator overloading. Boost.Python takes advantage of
this and makes it easy to wrap C++ operator-powered classes.</p>
C is well known for the abundance of operators. C++ extends this to the extremes
by allowing operator overloading. Boost.Python takes advantage of this and
makes it easy to wrap C++ operator-powered classes.
</p>
<p>
Consider a file position class <tt class="literal">FilePos</tt> and a set of operators that take
on FilePos instances:</p>
Consider a file position class <tt class="literal">FilePos</tt> and a set of operators
that take on FilePos instances:
</p>
<p></p>
<pre class="programlisting"><tt class="literal"><span class="keyword">class</span><span class="identifier"> FilePos</span><span class="special"> {</span><span class="comment"> /*...*/</span><span class="special"> };</span><span class="identifier">
<pre class="programlisting">
<span class="keyword">class</span> <span class="identifier">FilePos</span> <span class="special">{</span> <span class="comment">/*...*/</span> <span class="special">};</span>
FilePos</span><span class="keyword"> operator</span><span class="special">+(</span><span class="identifier">FilePos</span><span class="special">,</span><span class="keyword"> int</span><span class="special">);</span><span class="identifier">
FilePos</span><span class="keyword"> operator</span><span class="special">+(</span><span class="keyword">int</span><span class="special">,</span><span class="identifier"> FilePos</span><span class="special">);</span><span class="keyword">
int</span><span class="keyword"> operator</span><span class="special">-(</span><span class="identifier">FilePos</span><span class="special">,</span><span class="identifier"> FilePos</span><span class="special">);</span><span class="identifier">
FilePos</span><span class="keyword"> operator</span><span class="special">-(</span><span class="identifier">FilePos</span><span class="special">,</span><span class="keyword"> int</span><span class="special">);</span><span class="identifier">
FilePos</span><span class="special">&amp;</span><span class="keyword"> operator</span><span class="special">+=(</span><span class="identifier">FilePos</span><span class="special">&amp;,</span><span class="keyword"> int</span><span class="special">);</span><span class="identifier">
FilePos</span><span class="special">&amp;</span><span class="keyword"> operator</span><span class="special">-=(</span><span class="identifier">FilePos</span><span class="special">&amp;,</span><span class="keyword"> int</span><span class="special">);</span><span class="keyword">
bool</span><span class="keyword"> operator</span><span class="special">&lt;(</span><span class="identifier">FilePos</span><span class="special">,</span><span class="identifier"> FilePos</span><span class="special">);</span></tt></pre>
<span class="identifier">FilePos</span> <span class="keyword">operator</span><span class="special">+(</span><span class="identifier">FilePos</span><span class="special">,</span> <span class="keyword">int</span><span class="special">);</span>
<span class="identifier">FilePos</span> <span class="keyword">operator</span><span class="special">+(</span><span class="keyword">int</span><span class="special">,</span> <span class="identifier">FilePos</span><span class="special">);</span>
<span class="keyword">int</span> <span class="keyword">operator</span><span class="special">-(</span><span class="identifier">FilePos</span><span class="special">,</span> <span class="identifier">FilePos</span><span class="special">);</span>
<span class="identifier">FilePos</span> <span class="keyword">operator</span><span class="special">-(</span><span class="identifier">FilePos</span><span class="special">,</span> <span class="keyword">int</span><span class="special">);</span>
<span class="identifier">FilePos</span><span class="special">&amp;</span> <span class="keyword">operator</span><span class="special">+=(</span><span class="identifier">FilePos</span><span class="special">&amp;,</span> <span class="keyword">int</span><span class="special">);</span>
<span class="identifier">FilePos</span><span class="special">&amp;</span> <span class="keyword">operator</span><span class="special">-=(</span><span class="identifier">FilePos</span><span class="special">&amp;,</span> <span class="keyword">int</span><span class="special">);</span>
<span class="keyword">bool</span> <span class="keyword">operator</span><span class="special">&lt;(</span><span class="identifier">FilePos</span><span class="special">,</span> <span class="identifier">FilePos</span><span class="special">);</span>
</pre>
<p>
The class and the various operators can be mapped to Python rather easily
and intuitively:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">class_</span><span class="special">&lt;</span><span class="identifier">FilePos</span><span class="special">&gt;(</span><span class="string">"FilePos"</span><span class="special">)</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">self</span><span class="special"> +</span><span class="keyword"> int</span><span class="special">())</span><span class="comment"> // __add__
</span><span class="special"> .</span><span class="identifier">def</span><span class="special">(</span><span class="keyword">int</span><span class="special">()</span><span class="special"> +</span><span class="identifier"> self</span><span class="special">)</span><span class="comment"> // __radd__
</span><span class="special"> .</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">self</span><span class="special"> -</span><span class="identifier"> self</span><span class="special">)</span><span class="comment"> // __sub__
</span><span class="special"> .</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">self</span><span class="special"> -</span><span class="keyword"> int</span><span class="special">())</span><span class="comment"> // __sub__
</span><span class="special"> .</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">self</span><span class="special"> +=</span><span class="keyword"> int</span><span class="special">())</span><span class="comment"> // __iadd__
</span><span class="special"> .</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">self</span><span class="special"> -=</span><span class="identifier"> other</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;())</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">self</span><span class="special"> &lt;</span><span class="identifier"> self</span><span class="special">);</span><span class="comment"> // __lt__
</span></tt></pre>
The class and the various operators can be mapped to Python rather easily
and intuitively:
</p>
<pre class="programlisting">
<span class="identifier">class_</span><span class="special">&lt;</span><span class="identifier">FilePos</span><span class="special">&gt;(</span><span class="string">"FilePos"</span><span class="special">)</span>
<span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">self</span> <span class="special">+</span> <span class="keyword">int</span><span class="special">())</span> <span class="comment">// __add__
</span> <span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="keyword">int</span><span class="special">()</span> <span class="special">+</span> <span class="identifier">self</span><span class="special">)</span> <span class="comment">// __radd__
</span> <span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">self</span> <span class="special">-</span> <span class="identifier">self</span><span class="special">)</span> <span class="comment">// __sub__
</span> <span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">self</span> <span class="special">-</span> <span class="keyword">int</span><span class="special">())</span> <span class="comment">// __sub__
</span> <span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">self</span> <span class="special">+=</span> <span class="keyword">int</span><span class="special">())</span> <span class="comment">// __iadd__
</span> <span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">self</span> <span class="special">-=</span> <span class="identifier">other</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;())</span>
<span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">self</span> <span class="special">&lt;</span> <span class="identifier">self</span><span class="special">);</span> <span class="comment">// __lt__
</span></pre>
<p>
The code snippet above is very clear and needs almost no explanation at
all. It is virtually the same as the operators' signatures. Just take
note that <tt class="literal">self</tt> refers to FilePos object. Also, not every class <tt class="literal">T</tt> that
you might need to interact with in an operator expression is (cheaply)
default-constructible. You can use <tt class="literal">other&lt;T&gt;()</tt> in place of an actual
<tt class="literal">T</tt> instance when writing "self expressions".</p>
The code snippet above is very clear and needs almost no explanation at all.
It is virtually the same as the operators' signatures. Just take note that
<tt class="literal">self</tt> refers to FilePos object. Also, not every class
<tt class="literal">T</tt> that you might need to interact with in an operator
expression is (cheaply) default-constructible. You can use <tt class="literal">other&lt;T&gt;()</tt>
in place of an actual <tt class="literal">T</tt> instance when writing "self
expressions".
</p>
<a name="class_operators_special_functions.special_methods"></a><h2>
<a name="id448230"></a>Special Methods</h2>
<a name="id448698"></a>
Special Methods
</h2>
<p>
Python has a few more <span class="emphasis"><em>Special Methods</em></span>. Boost.Python supports all of the
standard special method names supported by real Python class instances. A
similar set of intuitive interfaces can also be used to wrap C++ functions
that correspond to these Python <span class="emphasis"><em>special functions</em></span>. Example:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">class</span><span class="identifier"> Rational</span><span class="special">
{</span><span class="keyword"> public</span><span class="special">:</span><span class="keyword"> operator</span><span class="keyword"> double</span><span class="special">()</span><span class="keyword"> const</span><span class="special">;</span><span class="special"> };</span><span class="identifier">
Python has a few more <span class="emphasis"><em>Special Methods</em></span>. Boost.Python
supports all of the standard special method names supported by real Python
class instances. A similar set of intuitive interfaces can also be used to
wrap C++ functions that correspond to these Python <span class="emphasis"><em>special functions</em></span>.
Example:
</p>
<pre class="programlisting">
<span class="keyword">class</span> <span class="identifier">Rational</span>
<span class="special">{</span> <span class="keyword">public</span><span class="special">:</span> <span class="keyword">operator</span> <span class="keyword">double</span><span class="special">()</span> <span class="keyword">const</span><span class="special">;</span> <span class="special">};</span>
Rational</span><span class="identifier"> pow</span><span class="special">(</span><span class="identifier">Rational</span><span class="special">,</span><span class="identifier"> Rational</span><span class="special">);</span><span class="identifier">
Rational</span><span class="identifier"> abs</span><span class="special">(</span><span class="identifier">Rational</span><span class="special">);</span><span class="identifier">
ostream</span><span class="special">&amp;</span><span class="keyword"> operator</span><span class="special">&lt;&lt;(</span><span class="identifier">ostream</span><span class="special">&amp;,</span><span class="identifier">Rational</span><span class="special">);</span><span class="identifier">
<span class="identifier">Rational</span> <span class="identifier">pow</span><span class="special">(</span><span class="identifier">Rational</span><span class="special">,</span> <span class="identifier">Rational</span><span class="special">);</span>
<span class="identifier">Rational</span> <span class="identifier">abs</span><span class="special">(</span><span class="identifier">Rational</span><span class="special">);</span>
<span class="identifier">ostream</span><span class="special">&amp;</span> <span class="keyword">operator</span><span class="special">&lt;&lt;(</span><span class="identifier">ostream</span><span class="special">&amp;,</span><span class="identifier">Rational</span><span class="special">);</span>
class_</span><span class="special">&lt;</span><span class="identifier">Rational</span><span class="special">&gt;(</span><span class="string">"Rational"</span><span class="special">)</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">float_</span><span class="special">(</span><span class="identifier">self</span><span class="special">))</span><span class="comment"> // __float__
</span><span class="special"> .</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">pow</span><span class="special">(</span><span class="identifier">self</span><span class="special">,</span><span class="identifier"> other</span><span class="special">&lt;</span><span class="identifier">Rational</span><span class="special">&gt;))</span><span class="comment"> // __pow__
</span><span class="special"> .</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">abs</span><span class="special">(</span><span class="identifier">self</span><span class="special">))</span><span class="comment"> // __abs__
</span><span class="special"> .</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">str</span><span class="special">(</span><span class="identifier">self</span><span class="special">))</span><span class="comment"> // __str__
</span><span class="special"> ;</span></tt></pre>
<span class="identifier">class_</span><span class="special">&lt;</span><span class="identifier">Rational</span><span class="special">&gt;(</span><span class="string">"Rational"</span><span class="special">)</span>
<span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">float_</span><span class="special">(</span><span class="identifier">self</span><span class="special">))</span> <span class="comment">// __float__
</span> <span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">pow</span><span class="special">(</span><span class="identifier">self</span><span class="special">,</span> <span class="identifier">other</span><span class="special">&lt;</span><span class="identifier">Rational</span><span class="special">&gt;))</span> <span class="comment">// __pow__
</span> <span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">abs</span><span class="special">(</span><span class="identifier">self</span><span class="special">))</span> <span class="comment">// __abs__
</span> <span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">str</span><span class="special">(</span><span class="identifier">self</span><span class="special">))</span> <span class="comment">// __str__
</span> <span class="special">;</span>
</pre>
<p>
Need we say more?</p>
Need we say more?
</p>
<div class="informaltable"><table class="table">
<colgroup><col></colgroup>
<tbody><tr><td class="blurb">
<span class="inlinemediaobject"><img src="../images/note.png"></span> What is the business of <tt class="computeroutput"><span class="keyword">operator</span><span class="special">&lt;&lt;</span></tt>?
Well, the method <tt class="computeroutput"><span class="identifier">str</span></tt> requires the <tt class="computeroutput"><span class="keyword">operator</span><span class="special">&lt;&lt;</span></tt> to do its work (i.e.
<tt class="computeroutput"><span class="keyword">operator</span><span class="special">&lt;&lt;</span></tt> is used by the method defined by <tt class="computeroutput"><span class="identifier">def</span><span class="special">(</span><span class="identifier">str</span><span class="special">(</span><span class="identifier">self</span><span class="special">))</span></tt>.</td></tr></tbody>
<span class="inlinemediaobject"><img src="../images/note.png"></span>
What is the business of <tt class="computeroutput"><span class="keyword">operator</span><span class="special">&lt;&lt;</span></tt>? Well, the method <tt class="computeroutput"><span class="identifier">str</span></tt> requires the <tt class="computeroutput"><span class="keyword">operator</span><span class="special">&lt;&lt;</span></tt> to do its work (i.e. <tt class="computeroutput"><span class="keyword">operator</span><span class="special">&lt;&lt;</span></tt>
is used by the method defined by <tt class="computeroutput"><span class="identifier">def</span><span class="special">(</span><span class="identifier">str</span><span class="special">(</span><span class="identifier">self</span><span class="special">))</span></tt>.</td></tr></tbody>
</table></div>
</div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><small>Copyright © 2002-2005 Joel de Guzman, David Abrahams</small></td>
<td align="right"><small>Copyright © 2002-2005 Joel
de Guzman, David Abrahams</small></td>
</tr></table>
<hr>
<div class="spirit-nav">

View File

@ -32,17 +32,18 @@
<dt><span class="section"><a href="functions.html#python.auto_overloading">Auto-Overloading</a></span></dt>
</dl></div>
<p>
In this chapter, we'll look at Boost.Python powered functions in closer
detail. We shall see some facilities to make exposing C++ functions to
Python safe from potential pifalls such as dangling pointers and
references. We shall also see facilities that will make it even easier for
us to expose C++ functions that take advantage of C++ features such as
overloading and default arguments.</p>
FunctionsIn this chapter, we'll look at Boost.Python powered functions in closer
detail. We shall see some facilities to make exposing C++ functions to Python
safe from potential pifalls such as dangling pointers and references. We shall
also see facilities that will make it even easier for us to expose C++ functions
that take advantage of C++ features such as overloading and default arguments.
</p>
<div class="blockquote"><blockquote class="blockquote"><p><span class="emphasis"><em>Read on...</em></span></p></blockquote></div>
<p>
But before you do, you might want to fire up Python 2.2 or later and type
<tt class="literal">&gt;&gt;&gt; import this</tt>.</p>
<pre class="programlisting"><tt class="literal">&gt;&gt;&gt; import this
But before you do, you might want to fire up Python 2.2 or later and type
<tt class="literal">&gt;&gt;&gt; import this</tt>.
</p>
<pre class="programlisting">&gt;&gt;&gt; import this
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
@ -63,187 +64,231 @@ Although never is often better than <span class="bold"><b>right</b></span> now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
</tt></pre>
</pre>
<div class="section" lang="en">
<div class="titlepage"><div><div><h3 class="title">
<a name="python.call_policies"></a>Call Policies</h3></div></div></div>
<p>
In C++, we often deal with arguments and return types such as pointers
and references. Such primitive types are rather, ummmm, low level and
they really don't tell us much. At the very least, we don't know the
owner of the pointer or the referenced object. No wonder languages
such as Java and Python never deal with such low level entities. In
C++, it's usually considered a good practice to use smart pointers
which exactly describe ownership semantics. Still, even good C++
interfaces use raw references and pointers sometimes, so Boost.Python
must deal with them. To do this, it may need your help. Consider the
following C++ function:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">X</span><span class="special">&amp;</span><span class="identifier"> f</span><span class="special">(</span><span class="identifier">Y</span><span class="special">&amp;</span><span class="identifier"> y</span><span class="special">,</span><span class="identifier"> Z</span><span class="special">*</span><span class="identifier"> z</span><span class="special">);</span></tt></pre>
Call PoliciesIn C++, we often deal with arguments and return types such as
pointers and references. Such primitive types are rather, ummmm, low level
and they really don't tell us much. At the very least, we don't know the
owner of the pointer or the referenced object. No wonder languages such as
Java and Python never deal with such low level entities. In C++, it's usually
considered a good practice to use smart pointers which exactly describe ownership
semantics. Still, even good C++ interfaces use raw references and pointers
sometimes, so Boost.Python must deal with them. To do this, it may need your
help. Consider the following C++ function:
</p>
<pre class="programlisting">
<span class="identifier">X</span><span class="special">&amp;</span> <span class="identifier">f</span><span class="special">(</span><span class="identifier">Y</span><span class="special">&amp;</span> <span class="identifier">y</span><span class="special">,</span> <span class="identifier">Z</span><span class="special">*</span> <span class="identifier">z</span><span class="special">);</span>
</pre>
<p>
How should the library wrap this function? A naive approach builds a
Python X object around result reference. This strategy might or might
not work out. Here's an example where it didn't</p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="identifier"> x</span><span class="special"> =</span><span class="identifier"> f</span><span class="special">(</span><span class="identifier">y</span><span class="special">,</span><span class="identifier"> z</span><span class="special">)</span> #<span class="identifier"> x</span><span class="identifier"> refers</span><span class="identifier"> to</span><span class="identifier"> some</span><span class="identifier"> C</span><span class="special">++</span><span class="identifier"> X</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> del</span><span class="identifier"> y</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> x</span><span class="special">.</span><span class="identifier">some_method</span><span class="special">()</span> #<span class="identifier"> CRASH</span><span class="special">!</span></tt></pre>
How should the library wrap this function? A naive approach builds a Python
X object around result reference. This strategy might or might not work out.
Here's an example where it didn't
</p>
<pre class="programlisting">
<span class="special">&gt;&gt;&gt;</span> <span class="identifier">x</span> <span class="special">=</span> <span class="identifier">f</span><span class="special">(</span><span class="identifier">y</span><span class="special">,</span> <span class="identifier">z</span><span class="special">)</span> # <span class="identifier">x</span> <span class="identifier">refers</span> <span class="identifier">to</span> <span class="identifier">some</span> <span class="identifier">C</span><span class="special">++</span> <span class="identifier">X</span>
<span class="special">&gt;&gt;&gt;</span> <span class="identifier">del</span> <span class="identifier">y</span>
<span class="special">&gt;&gt;&gt;</span> <span class="identifier">x</span><span class="special">.</span><span class="identifier">some_method</span><span class="special">()</span> # <span class="identifier">CRASH</span><span class="special">!</span>
</pre>
<p>
What's the problem?</p>
What's the problem?
</p>
<p>
Well, what if f() was implemented as shown below:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">X</span><span class="special">&amp;</span><span class="identifier"> f</span><span class="special">(</span><span class="identifier">Y</span><span class="special">&amp;</span><span class="identifier"> y</span><span class="special">,</span><span class="identifier"> Z</span><span class="special">*</span><span class="identifier"> z</span><span class="special">)</span><span class="special">
{</span><span class="identifier">
y</span><span class="special">.</span><span class="identifier">z</span><span class="special"> =</span><span class="identifier"> z</span><span class="special">;</span><span class="keyword">
return</span><span class="identifier"> y</span><span class="special">.</span><span class="identifier">x</span><span class="special">;</span><span class="special">
}</span></tt></pre>
Well, what if f() was implemented as shown below:
</p>
<pre class="programlisting">
<span class="identifier">X</span><span class="special">&amp;</span> <span class="identifier">f</span><span class="special">(</span><span class="identifier">Y</span><span class="special">&amp;</span> <span class="identifier">y</span><span class="special">,</span> <span class="identifier">Z</span><span class="special">*</span> <span class="identifier">z</span><span class="special">)</span>
<span class="special">{</span>
<span class="identifier">y</span><span class="special">.</span><span class="identifier">z</span> <span class="special">=</span> <span class="identifier">z</span><span class="special">;</span>
<span class="keyword">return</span> <span class="identifier">y</span><span class="special">.</span><span class="identifier">x</span><span class="special">;</span>
<span class="special">}</span>
</pre>
<p>
The problem is that the lifetime of result X&amp; is tied to the lifetime
of y, because the f() returns a reference to a member of the y
object. This idiom is is not uncommon and perfectly acceptable in the
context of C++. However, Python users should not be able to crash the
system just by using our C++ interface. In this case deleting y will
invalidate the reference to X. We have a dangling reference.</p>
The problem is that the lifetime of result X&amp; is tied to the lifetime
of y, because the f() returns a reference to a member of the y object. This
idiom is is not uncommon and perfectly acceptable in the context of C++.
However, Python users should not be able to crash the system just by using
our C++ interface. In this case deleting y will invalidate the reference
to X. We have a dangling reference.
</p>
<p>
Here's what's happening:</p>
Here's what's happening:
</p>
<div class="orderedlist"><ol type="1">
<li>
<tt class="literal">f</tt> is called passing in a reference to <tt class="literal">y</tt> and a pointer to <tt class="literal">z</tt>
<tt class="literal">f</tt> is called passing in a reference to <tt class="literal">y</tt>
and a pointer to <tt class="literal">z</tt>
</li>
<li>
A reference to <tt class="literal">y.x</tt> is returned
</li>
A reference to <tt class="literal">y.x</tt> is returned
</li>
<li>
<tt class="literal">y</tt> is deleted. <tt class="literal">x</tt> is a dangling reference
</li>
</li>
<li>
<tt class="literal">x.some_method()</tt> is called
</li>
</li>
<li><span class="bold"><b>BOOM!</b></span></li>
</ol></div>
<p>
We could copy result into a new object:</p>
We could copy result into a new object:
</p>
<p></p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="identifier"> f</span><span class="special">(</span><span class="identifier">y</span><span class="special">,</span><span class="identifier"> z</span><span class="special">).</span><span class="identifier">set</span><span class="special">(</span><span class="number">42</span><span class="special">)</span><span class="comment"> # Result disappears
</span><span class="special">&gt;&gt;&gt;</span><span class="identifier"> y</span><span class="special">.</span><span class="identifier">x</span><span class="special">.</span><span class="identifier">get</span><span class="special">()</span><span class="comment"> # No crash, but still bad
</span><span class="number">3.14</span></tt></pre>
<pre class="programlisting">
<span class="special">&gt;&gt;&gt;</span> <span class="identifier">f</span><span class="special">(</span><span class="identifier">y</span><span class="special">,</span> <span class="identifier">z</span><span class="special">).</span><span class="identifier">set</span><span class="special">(</span><span class="number">42</span><span class="special">)</span> <span class="comment"># Result disappears
</span><span class="special">&gt;&gt;&gt;</span> <span class="identifier">y</span><span class="special">.</span><span class="identifier">x</span><span class="special">.</span><span class="identifier">get</span><span class="special">()</span> <span class="comment"># No crash, but still bad
</span><span class="number">3.14</span>
</pre>
<p>
This is not really our intent of our C++ interface. We've broken our
promise that the Python interface should reflect the C++ interface as
closely as possible.</p>
This is not really our intent of our C++ interface. We've broken our promise
that the Python interface should reflect the C++ interface as closely as
possible.
</p>
<p>
Our problems do not end there. Suppose Y is implemented as follows:</p>
Our problems do not end there. Suppose Y is implemented as follows:
</p>
<p></p>
<pre class="programlisting"><tt class="literal"><span class="keyword">struct</span><span class="identifier"> Y</span><span class="special">
{</span><span class="identifier">
X</span><span class="identifier"> x</span><span class="special">;</span><span class="identifier"> Z</span><span class="special">*</span><span class="identifier"> z</span><span class="special">;</span><span class="keyword">
int</span><span class="identifier"> z_value</span><span class="special">()</span><span class="special"> {</span><span class="keyword"> return</span><span class="identifier"> z</span><span class="special">-&gt;</span><span class="identifier">value</span><span class="special">();</span><span class="special"> }</span><span class="special">
};</span></tt></pre>
<pre class="programlisting">
<span class="keyword">struct</span> <span class="identifier">Y</span>
<span class="special">{</span>
<span class="identifier">X</span> <span class="identifier">x</span><span class="special">;</span> <span class="identifier">Z</span><span class="special">*</span> <span class="identifier">z</span><span class="special">;</span>
<span class="keyword">int</span> <span class="identifier">z_value</span><span class="special">()</span> <span class="special">{</span> <span class="keyword">return</span> <span class="identifier">z</span><span class="special">-&gt;</span><span class="identifier">value</span><span class="special">();</span> <span class="special">}</span>
<span class="special">};</span>
</pre>
<p>
Notice that the data member <tt class="literal">z</tt> is held by class Y using a raw
pointer. Now we have a potential dangling pointer problem inside Y:</p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="identifier"> x</span><span class="special"> =</span><span class="identifier"> f</span><span class="special">(</span><span class="identifier">y</span><span class="special">,</span><span class="identifier"> z</span><span class="special">)</span> #<span class="identifier"> y</span><span class="identifier"> refers</span><span class="identifier"> to</span><span class="identifier"> z</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> del</span><span class="identifier"> z</span>       #<span class="identifier"> Kill</span><span class="identifier"> the</span><span class="identifier"> z</span><span class="identifier"> object</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> y</span><span class="special">.</span><span class="identifier">z_value</span><span class="special">()</span> #<span class="identifier"> CRASH</span><span class="special">!</span></tt></pre>
Notice that the data member <tt class="literal">z</tt> is held by class Y using
a raw pointer. Now we have a potential dangling pointer problem inside Y:
</p>
<pre class="programlisting">
<span class="special">&gt;&gt;&gt;</span> <span class="identifier">x</span> <span class="special">=</span> <span class="identifier">f</span><span class="special">(</span><span class="identifier">y</span><span class="special">,</span> <span class="identifier">z</span><span class="special">)</span> # <span class="identifier">y</span> <span class="identifier">refers</span> <span class="identifier">to</span> <span class="identifier">z</span>
<span class="special">&gt;&gt;&gt;</span> <span class="identifier">del</span> <span class="identifier">z</span> # <span class="identifier">Kill</span> <span class="identifier">the</span> <span class="identifier">z</span> <span class="identifier">object</span>
<span class="special">&gt;&gt;&gt;</span> <span class="identifier">y</span><span class="special">.</span><span class="identifier">z_value</span><span class="special">()</span> # <span class="identifier">CRASH</span><span class="special">!</span>
</pre>
<p>
For reference, here's the implementation of <tt class="literal">f</tt> again:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">X</span><span class="special">&amp;</span><span class="identifier"> f</span><span class="special">(</span><span class="identifier">Y</span><span class="special">&amp;</span><span class="identifier"> y</span><span class="special">,</span><span class="identifier"> Z</span><span class="special">*</span><span class="identifier"> z</span><span class="special">)</span><span class="special">
{</span><span class="identifier">
y</span><span class="special">.</span><span class="identifier">z</span><span class="special"> =</span><span class="identifier"> z</span><span class="special">;</span><span class="keyword">
return</span><span class="identifier"> y</span><span class="special">.</span><span class="identifier">x</span><span class="special">;</span><span class="special">
}</span></tt></pre>
For reference, here's the implementation of <tt class="literal">f</tt> again:
</p>
<pre class="programlisting">
<span class="identifier">X</span><span class="special">&amp;</span> <span class="identifier">f</span><span class="special">(</span><span class="identifier">Y</span><span class="special">&amp;</span> <span class="identifier">y</span><span class="special">,</span> <span class="identifier">Z</span><span class="special">*</span> <span class="identifier">z</span><span class="special">)</span>
<span class="special">{</span>
<span class="identifier">y</span><span class="special">.</span><span class="identifier">z</span> <span class="special">=</span> <span class="identifier">z</span><span class="special">;</span>
<span class="keyword">return</span> <span class="identifier">y</span><span class="special">.</span><span class="identifier">x</span><span class="special">;</span>
<span class="special">}</span>
</pre>
<p>
Here's what's happening:</p>
Here's what's happening:
</p>
<div class="orderedlist"><ol type="1">
<li>
<tt class="literal">f</tt> is called passing in a reference to <tt class="literal">y</tt> and a pointer to <tt class="literal">z</tt>
<tt class="literal">f</tt> is called passing in a reference to <tt class="literal">y</tt>
and a pointer to <tt class="literal">z</tt>
</li>
<li>
A pointer to <tt class="literal">z</tt> is held by <tt class="literal">y</tt>
A pointer to <tt class="literal">z</tt> is held by <tt class="literal">y</tt>
</li>
<li>
A reference to <tt class="literal">y.x</tt> is returned
</li>
A reference to <tt class="literal">y.x</tt> is returned
</li>
<li>
<tt class="literal">z</tt> is deleted. <tt class="literal">y.z</tt> is a dangling pointer
</li>
</li>
<li>
<tt class="literal">y.z_value()</tt> is called
</li>
</li>
<li>
<tt class="literal">z-&gt;value()</tt> is called
</li>
</li>
<li><span class="bold"><b>BOOM!</b></span></li>
</ol></div>
<a name="call_policies.call_policies"></a><h2>
<a name="id449896"></a>Call Policies</h2>
<a name="id450599"></a>
Call Policies
</h2>
<p>
Call Policies may be used in situations such as the example detailed above.
In our example, <tt class="literal">return_internal_reference</tt> and <tt class="literal">with_custodian_and_ward</tt>
are our friends:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span><span class="identifier"> f</span><span class="special">,</span><span class="identifier">
return_internal_reference</span><span class="special">&lt;</span><span class="number">1</span><span class="special">,</span><span class="identifier">
with_custodian_and_ward</span><span class="special">&lt;</span><span class="number">1</span><span class="special">,</span><span class="number"> 2</span><span class="special">&gt;</span><span class="special"> &gt;());</span></tt></pre>
Call Policies may be used in situations such as the example detailed above.
In our example, <tt class="literal">return_internal_reference</tt> and <tt class="literal">with_custodian_and_ward</tt>
are our friends:
</p>
<pre class="programlisting">
<span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span> <span class="identifier">f</span><span class="special">,</span>
<span class="identifier">return_internal_reference</span><span class="special">&lt;</span><span class="number">1</span><span class="special">,</span>
<span class="identifier">with_custodian_and_ward</span><span class="special">&lt;</span><span class="number">1</span><span class="special">,</span> <span class="number">2</span><span class="special">&gt;</span> <span class="special">&gt;());</span>
</pre>
<p>
What are the <tt class="literal">1</tt> and <tt class="literal">2</tt> parameters, you ask?</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">return_internal_reference</span><span class="special">&lt;</span><span class="number">1</span></tt></pre>
What are the <tt class="literal">1</tt> and <tt class="literal">2</tt> parameters, you
ask?
</p>
<pre class="programlisting">
<span class="identifier">return_internal_reference</span><span class="special">&lt;</span><span class="number">1</span>
</pre>
<p>
Informs Boost.Python that the first argument, in our case <tt class="literal">Y&amp; y</tt>, is the
owner of the returned reference: <tt class="literal">X&amp;</tt>. The "<tt class="literal">1</tt>" simply specifies the
first argument. In short: "return an internal reference <tt class="literal">X&amp;</tt> owned by the
1st argument <tt class="literal">Y&amp; y</tt>".</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">with_custodian_and_ward</span><span class="special">&lt;</span><span class="number">1</span><span class="special">,</span><span class="number"> 2</span><span class="special">&gt;</span></tt></pre>
Informs Boost.Python that the first argument, in our case <tt class="literal">Y&amp;
y</tt>, is the owner of the returned reference: <tt class="literal">X&amp;</tt>.
The "<tt class="literal">1</tt>" simply specifies the first argument.
In short: "return an internal reference <tt class="literal">X&amp;</tt> owned
by the 1st argument <tt class="literal">Y&amp; y</tt>".
</p>
<pre class="programlisting">
<span class="identifier">with_custodian_and_ward</span><span class="special">&lt;</span><span class="number">1</span><span class="special">,</span> <span class="number">2</span><span class="special">&gt;</span>
</pre>
<p>
Informs Boost.Python that the lifetime of the argument indicated by ward
(i.e. the 2nd argument: <tt class="literal">Z* z</tt>) is dependent on the lifetime of the
argument indicated by custodian (i.e. the 1st argument: <tt class="literal">Y&amp; y</tt>).</p>
Informs Boost.Python that the lifetime of the argument indicated by ward
(i.e. the 2nd argument: <tt class="literal">Z* z</tt>) is dependent on the lifetime
of the argument indicated by custodian (i.e. the 1st argument: <tt class="literal">Y&amp;
y</tt>).
</p>
<p>
It is also important to note that we have defined two policies above. Two
or more policies can be composed by chaining. Here's the general syntax:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">policy1</span><span class="special">&lt;</span><span class="identifier">args</span><span class="special">...,</span><span class="identifier">
policy2</span><span class="special">&lt;</span><span class="identifier">args</span><span class="special">...,</span><span class="identifier">
policy3</span><span class="special">&lt;</span><span class="identifier">args</span><span class="special">...&gt;</span><span class="special"> &gt;</span><span class="special"> &gt;</span></tt></pre>
It is also important to note that we have defined two policies above. Two
or more policies can be composed by chaining. Here's the general syntax:
</p>
<pre class="programlisting">
<span class="identifier">policy1</span><span class="special">&lt;</span><span class="identifier">args</span><span class="special">...,</span>
<span class="identifier">policy2</span><span class="special">&lt;</span><span class="identifier">args</span><span class="special">...,</span>
<span class="identifier">policy3</span><span class="special">&lt;</span><span class="identifier">args</span><span class="special">...&gt;</span> <span class="special">&gt;</span> <span class="special">&gt;</span>
</pre>
<p>
Here is the list of predefined call policies. A complete reference detailing
these can be found <a href="../../../../v2/reference.html#models_of_call_policies" target="_top">here</a>.</p>
Here is the list of predefined call policies. A complete reference detailing
these can be found <a href="../../../../v2/reference.html#models_of_call_policies" target="_top">here</a>.
</p>
<div class="itemizedlist"><ul type="disc">
<li>
<span class="bold"><b>with_custodian_and_ward</b></span><br>
Ties lifetimes of the arguments
</li>
<span class="bold"><b>with_custodian_and_ward</b></span><br> Ties lifetimes
of the arguments
</li>
<li>
<span class="bold"><b>with_custodian_and_ward_postcall</b></span><br>
Ties lifetimes of the arguments and results
</li>
Ties lifetimes of the arguments and results
</li>
<li>
<span class="bold"><b>return_internal_reference</b></span><br>
Ties lifetime of one argument to that of result
</li>
<span class="bold"><b>return_internal_reference</b></span><br> Ties lifetime
of one argument to that of result
</li>
<li>
<span class="bold"><b>return_value_policy&lt;T&gt; with T one of:</b></span><br>
</li>
<li>
<span class="bold"><b>reference_existing_object</b></span><br>
naive (dangerous) approach
</li>
<span class="bold"><b>reference_existing_object</b></span><br> naive
(dangerous) approach
</li>
<li>
<span class="bold"><b>copy_const_reference</b></span><br>
Boost.Python v1 approach
</li>
<span class="bold"><b>copy_const_reference</b></span><br> Boost.Python
v1 approach
</li>
<li>
<span class="bold"><b>copy_non_const_reference</b></span><br>
</li>
<li>
<span class="bold"><b>manage_new_object</b></span><br>
Adopt a pointer and hold the instance
</li>
<span class="bold"><b>manage_new_object</b></span><br> Adopt a pointer
and hold the instance
</li>
</ul></div>
<div class="informaltable"><table class="table">
<colgroup><col></colgroup>
<tbody><tr><td class="blurb">
<span class="inlinemediaobject"><img src="../images/smiley.png"></span><span class="bold"><b>Remember the Zen, Luke:</b></span><br><br>
"Explicit is better than implicit"<br>
"In the face of ambiguity, refuse the temptation to guess"<br>
<span class="inlinemediaobject"><img src="../images/smiley.png"></span> <span class="bold"><b>Remember the Zen, Luke:</b></span><br><br> "Explicit
is better than implicit"<br> "In the face of ambiguity,
refuse the temptation to guess"<br>
</td></tr></tbody>
</table></div>
</div>
@ -251,226 +296,303 @@ Boost.Python v1 approach
<div class="titlepage"><div><div><h3 class="title">
<a name="python.overloading"></a>Overloading</h3></div></div></div>
<p>
The following illustrates a scheme for manually wrapping an overloaded
member functions. Of course, the same technique can be applied to wrapping
overloaded non-member functions.</p>
OverloadingThe following illustrates a scheme for manually wrapping an overloaded
member functions. Of course, the same technique can be applied to wrapping
overloaded non-member functions.
</p>
<p>
We have here our C++ class:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">struct</span><span class="identifier"> X</span><span class="special">
{</span><span class="keyword">
bool</span><span class="identifier"> f</span><span class="special">(</span><span class="keyword">int</span><span class="identifier"> a</span><span class="special">)</span><span class="special">
{</span><span class="keyword">
return</span><span class="keyword"> true</span><span class="special">;</span><span class="special">
}</span><span class="keyword">
We have here our C++ class:
</p>
<pre class="programlisting">
<span class="keyword">struct</span> <span class="identifier">X</span>
<span class="special">{</span>
<span class="keyword">bool</span> <span class="identifier">f</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">a</span><span class="special">)</span>
<span class="special">{</span>
<span class="keyword">return</span> <span class="keyword">true</span><span class="special">;</span>
<span class="special">}</span>
bool</span><span class="identifier"> f</span><span class="special">(</span><span class="keyword">int</span><span class="identifier"> a</span><span class="special">,</span><span class="keyword"> double</span><span class="identifier"> b</span><span class="special">)</span><span class="special">
{</span><span class="keyword">
return</span><span class="keyword"> true</span><span class="special">;</span><span class="special">
}</span><span class="keyword">
<span class="keyword">bool</span> <span class="identifier">f</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">a</span><span class="special">,</span> <span class="keyword">double</span> <span class="identifier">b</span><span class="special">)</span>
<span class="special">{</span>
<span class="keyword">return</span> <span class="keyword">true</span><span class="special">;</span>
<span class="special">}</span>
bool</span><span class="identifier"> f</span><span class="special">(</span><span class="keyword">int</span><span class="identifier"> a</span><span class="special">,</span><span class="keyword"> double</span><span class="identifier"> b</span><span class="special">,</span><span class="keyword"> char</span><span class="identifier"> c</span><span class="special">)</span><span class="special">
{</span><span class="keyword">
return</span><span class="keyword"> true</span><span class="special">;</span><span class="special">
}</span><span class="keyword">
<span class="keyword">bool</span> <span class="identifier">f</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">a</span><span class="special">,</span> <span class="keyword">double</span> <span class="identifier">b</span><span class="special">,</span> <span class="keyword">char</span> <span class="identifier">c</span><span class="special">)</span>
<span class="special">{</span>
<span class="keyword">return</span> <span class="keyword">true</span><span class="special">;</span>
<span class="special">}</span>
int</span><span class="identifier"> f</span><span class="special">(</span><span class="keyword">int</span><span class="identifier"> a</span><span class="special">,</span><span class="keyword"> int</span><span class="identifier"> b</span><span class="special">,</span><span class="keyword"> int</span><span class="identifier"> c</span><span class="special">)</span><span class="special">
{</span><span class="keyword">
return</span><span class="identifier"> a</span><span class="special"> +</span><span class="identifier"> b</span><span class="special"> +</span><span class="identifier"> c</span><span class="special">;</span><span class="special">
};</span><span class="special">
};</span></tt></pre>
<span class="keyword">int</span> <span class="identifier">f</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">a</span><span class="special">,</span> <span class="keyword">int</span> <span class="identifier">b</span><span class="special">,</span> <span class="keyword">int</span> <span class="identifier">c</span><span class="special">)</span>
<span class="special">{</span>
<span class="keyword">return</span> <span class="identifier">a</span> <span class="special">+</span> <span class="identifier">b</span> <span class="special">+</span> <span class="identifier">c</span><span class="special">;</span>
<span class="special">};</span>
<span class="special">};</span>
</pre>
<p>
Class X has 4 overloaded functions. We shall start by introducing some
member function pointer variables:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">bool</span><span class="special"> (</span><span class="identifier">X</span><span class="special">::*</span><span class="identifier">fx1</span><span class="special">)(</span><span class="keyword">int</span><span class="special">)</span><span class="special"> =</span><span class="special"> &amp;</span><span class="identifier">X</span><span class="special">::</span><span class="identifier">f</span><span class="special">;</span><span class="keyword">
bool</span><span class="special"> (</span><span class="identifier">X</span><span class="special">::*</span><span class="identifier">fx2</span><span class="special">)(</span><span class="keyword">int</span><span class="special">,</span><span class="keyword"> double</span><span class="special">)</span><span class="special"> =</span><span class="special"> &amp;</span><span class="identifier">X</span><span class="special">::</span><span class="identifier">f</span><span class="special">;</span><span class="keyword">
bool</span><span class="special"> (</span><span class="identifier">X</span><span class="special">::*</span><span class="identifier">fx3</span><span class="special">)(</span><span class="keyword">int</span><span class="special">,</span><span class="keyword"> double</span><span class="special">,</span><span class="keyword"> char</span><span class="special">)=</span><span class="special"> &amp;</span><span class="identifier">X</span><span class="special">::</span><span class="identifier">f</span><span class="special">;</span><span class="keyword">
int</span><span class="special"> (</span><span class="identifier">X</span><span class="special">::*</span><span class="identifier">fx4</span><span class="special">)(</span><span class="keyword">int</span><span class="special">,</span><span class="keyword"> int</span><span class="special">,</span><span class="keyword"> int</span><span class="special">)</span><span class="special"> =</span><span class="special"> &amp;</span><span class="identifier">X</span><span class="special">::</span><span class="identifier">f</span><span class="special">;</span></tt></pre>
Class X has 4 overloaded functions. We shall start by introducing some member
function pointer variables:
</p>
<pre class="programlisting">
<span class="keyword">bool</span> <span class="special">(</span><span class="identifier">X</span><span class="special">::*</span><span class="identifier">fx1</span><span class="special">)(</span><span class="keyword">int</span><span class="special">)</span> <span class="special">=</span> <span class="special">&amp;</span><span class="identifier">X</span><span class="special">::</span><span class="identifier">f</span><span class="special">;</span>
<span class="keyword">bool</span> <span class="special">(</span><span class="identifier">X</span><span class="special">::*</span><span class="identifier">fx2</span><span class="special">)(</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">double</span><span class="special">)</span> <span class="special">=</span> <span class="special">&amp;</span><span class="identifier">X</span><span class="special">::</span><span class="identifier">f</span><span class="special">;</span>
<span class="keyword">bool</span> <span class="special">(</span><span class="identifier">X</span><span class="special">::*</span><span class="identifier">fx3</span><span class="special">)(</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">double</span><span class="special">,</span> <span class="keyword">char</span><span class="special">)=</span> <span class="special">&amp;</span><span class="identifier">X</span><span class="special">::</span><span class="identifier">f</span><span class="special">;</span>
<span class="keyword">int</span> <span class="special">(</span><span class="identifier">X</span><span class="special">::*</span><span class="identifier">fx4</span><span class="special">)(</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">int</span><span class="special">,</span> <span class="keyword">int</span><span class="special">)</span> <span class="special">=</span> <span class="special">&amp;</span><span class="identifier">X</span><span class="special">::</span><span class="identifier">f</span><span class="special">;</span>
</pre>
<p>
With these in hand, we can proceed to define and wrap this for Python:</p>
<pre class="programlisting"><tt class="literal"><span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span><span class="identifier"> fx1</span><span class="special">)</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span><span class="identifier"> fx2</span><span class="special">)</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span><span class="identifier"> fx3</span><span class="special">)</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span><span class="identifier"> fx4</span><span class="special">)</span></tt></pre>
With these in hand, we can proceed to define and wrap this for Python:
</p>
<pre class="programlisting">
<span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span> <span class="identifier">fx1</span><span class="special">)</span>
<span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span> <span class="identifier">fx2</span><span class="special">)</span>
<span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span> <span class="identifier">fx3</span><span class="special">)</span>
<span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span> <span class="identifier">fx4</span><span class="special">)</span>
</pre>
</div>
<div class="section" lang="en">
<div class="titlepage"><div><div><h3 class="title">
<a name="python.default_arguments"></a>Default Arguments</h3></div></div></div>
<p>
Boost.Python wraps (member) function pointers. Unfortunately, C++ function
pointers carry no default argument info. Take a function <tt class="literal">f</tt> with default
arguments:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">int</span><span class="identifier"> f</span><span class="special">(</span><span class="keyword">int</span><span class="special">,</span><span class="keyword"> double</span><span class="special"> =</span><span class="number"> 3.14</span><span class="special">,</span><span class="keyword"> char</span><span class="keyword"> const</span><span class="special">*</span><span class="special"> =</span><span class="string"> "hello"</span><span class="special">);</span></tt></pre>
Default ArgumentsBoost.Python wraps (member) function pointers. Unfortunately,
C++ function pointers carry no default argument info. Take a function <tt class="literal">f</tt>
with default arguments:
</p>
<pre class="programlisting">
<span class="keyword">int</span> <span class="identifier">f</span><span class="special">(</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">double</span> <span class="special">=</span> <span class="number">3.14</span><span class="special">,</span> <span class="keyword">char</span> <span class="keyword">const</span><span class="special">*</span> <span class="special">=</span> <span class="string">"hello"</span><span class="special">);</span>
</pre>
<p>
But the type of a pointer to the function <tt class="literal">f</tt> has no information
about its default arguments:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">int</span><span class="special">(*</span><span class="identifier">g</span><span class="special">)(</span><span class="keyword">int</span><span class="special">,</span><span class="keyword">double</span><span class="special">,</span><span class="keyword">char</span><span class="keyword"> const</span><span class="special">*)</span><span class="special"> =</span><span class="identifier"> f</span><span class="special">;</span><span class="comment"> // defaults lost!
</span></tt></pre>
But the type of a pointer to the function <tt class="literal">f</tt> has no information
about its default arguments:
</p>
<pre class="programlisting">
<span class="keyword">int</span><span class="special">(*</span><span class="identifier">g</span><span class="special">)(</span><span class="keyword">int</span><span class="special">,</span><span class="keyword">double</span><span class="special">,</span><span class="keyword">char</span> <span class="keyword">const</span><span class="special">*)</span> <span class="special">=</span> <span class="identifier">f</span><span class="special">;</span> <span class="comment">// defaults lost!
</span></pre>
<p>
When we pass this function pointer to the <tt class="literal">def</tt> function, there is no way
to retrieve the default arguments:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span><span class="identifier"> f</span><span class="special">);</span><span class="comment"> // defaults lost!
</span></tt></pre>
When we pass this function pointer to the <tt class="literal">def</tt> function,
there is no way to retrieve the default arguments:
</p>
<pre class="programlisting">
<span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span> <span class="identifier">f</span><span class="special">);</span> <span class="comment">// defaults lost!
</span></pre>
<p>
Because of this, when wrapping C++ code, we had to resort to manual
wrapping as outlined in the <a href="functions.html#python.overloading" title="Overloading">previous section</a>, or
writing thin wrappers:</p>
<pre class="programlisting"><tt class="literal"><span class="comment">// write "thin wrappers"
</span><span class="keyword">int</span><span class="identifier"> f1</span><span class="special">(</span><span class="keyword">int</span><span class="identifier"> x</span><span class="special">)</span><span class="special"> {</span><span class="identifier"> f</span><span class="special">(</span><span class="identifier">x</span><span class="special">);</span><span class="special"> }</span><span class="keyword">
int</span><span class="identifier"> f2</span><span class="special">(</span><span class="keyword">int</span><span class="identifier"> x</span><span class="special">,</span><span class="keyword"> double</span><span class="identifier"> y</span><span class="special">)</span><span class="special"> {</span><span class="identifier"> f</span><span class="special">(</span><span class="identifier">x</span><span class="special">,</span><span class="identifier">y</span><span class="special">);</span><span class="special"> }</span><span class="comment">
Because of this, when wrapping C++ code, we had to resort to manual wrapping
as outlined in the <a href="functions.html#python.overloading" title="Overloading">previous section</a>,
or writing thin wrappers:
</p>
<pre class="programlisting">
<span class="comment">// write "thin wrappers"
</span><span class="keyword">int</span> <span class="identifier">f1</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">x</span><span class="special">)</span> <span class="special">{</span> <span class="identifier">f</span><span class="special">(</span><span class="identifier">x</span><span class="special">);</span> <span class="special">}</span>
<span class="keyword">int</span> <span class="identifier">f2</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">x</span><span class="special">,</span> <span class="keyword">double</span> <span class="identifier">y</span><span class="special">)</span> <span class="special">{</span> <span class="identifier">f</span><span class="special">(</span><span class="identifier">x</span><span class="special">,</span><span class="identifier">y</span><span class="special">);</span> <span class="special">}</span>
/*...*/
<span class="comment">/*...*/</span>
// in module init
</span><span class="identifier"> def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span><span class="identifier"> f</span><span class="special">);</span><span class="comment"> // all arguments
</span><span class="identifier"> def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span><span class="identifier"> f2</span><span class="special">);</span><span class="comment"> // two arguments
</span><span class="identifier"> def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span><span class="identifier"> f1</span><span class="special">);</span><span class="comment"> // one argument
</span></tt></pre>
<span class="comment">// in module init
</span> <span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span> <span class="identifier">f</span><span class="special">);</span> <span class="comment">// all arguments
</span> <span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span> <span class="identifier">f2</span><span class="special">);</span> <span class="comment">// two arguments
</span> <span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span> <span class="identifier">f1</span><span class="special">);</span> <span class="comment">// one argument
</span></pre>
<p>
When you want to wrap functions (or member functions) that either:</p>
When you want to wrap functions (or member functions) that either:
</p>
<div class="itemizedlist"><ul type="disc">
<li>
have default arguments, or
</li>
have default arguments, or
</li>
<li>
are overloaded with a common sequence of initial arguments
</li>
are overloaded with a common sequence of initial arguments
</li>
</ul></div>
<a name="default_arguments.boost_python_function_overloads"></a><h2>
<a name="id451716"></a>BOOST_PYTHON_FUNCTION_OVERLOADS</h2>
<a name="id452559"></a>
BOOST_PYTHON_FUNCTION_OVERLOADS
</h2>
<p>
Boost.Python now has a way to make it easier. For instance, given a function:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">int</span><span class="identifier"> foo</span><span class="special">(</span><span class="keyword">int</span><span class="identifier"> a</span><span class="special">,</span><span class="keyword"> char</span><span class="identifier"> b</span><span class="special"> =</span><span class="number"> 1</span><span class="special">,</span><span class="keyword"> unsigned</span><span class="identifier"> c</span><span class="special"> =</span><span class="number"> 2</span><span class="special">,</span><span class="keyword"> double</span><span class="identifier"> d</span><span class="special"> =</span><span class="number"> 3</span><span class="special">)</span><span class="special">
{</span><span class="comment">
/*...*/</span><span class="special">
}</span></tt></pre>
Boost.Python now has a way to make it easier. For instance, given a function:
</p>
<pre class="programlisting">
<span class="keyword">int</span> <span class="identifier">foo</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">a</span><span class="special">,</span> <span class="keyword">char</span> <span class="identifier">b</span> <span class="special">=</span> <span class="number">1</span><span class="special">,</span> <span class="keyword">unsigned</span> <span class="identifier">c</span> <span class="special">=</span> <span class="number">2</span><span class="special">,</span> <span class="keyword">double</span> <span class="identifier">d</span> <span class="special">=</span> <span class="number">3</span><span class="special">)</span>
<span class="special">{</span>
<span class="comment">/*...*/</span>
<span class="special">}</span>
</pre>
<p>
The macro invocation:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">BOOST_PYTHON_FUNCTION_OVERLOADS</span><span class="special">(</span><span class="identifier">foo_overloads</span><span class="special">,</span><span class="identifier"> foo</span><span class="special">,</span><span class="number"> 1</span><span class="special">,</span><span class="number"> 4</span><span class="special">)</span></tt></pre>
The macro invocation:
</p>
<pre class="programlisting">
<span class="identifier">BOOST_PYTHON_FUNCTION_OVERLOADS</span><span class="special">(</span><span class="identifier">foo_overloads</span><span class="special">,</span> <span class="identifier">foo</span><span class="special">,</span> <span class="number">1</span><span class="special">,</span> <span class="number">4</span><span class="special">)</span>
</pre>
<p>
will automatically create the thin wrappers for us. This macro will create
a class <tt class="literal">foo_overloads</tt> that can be passed on to <tt class="literal">def(...)</tt>. The third
and fourth macro argument are the minimum arguments and maximum arguments,
respectively. In our <tt class="literal">foo</tt> function the minimum number of arguments is 1
and the maximum number of arguments is 4. The <tt class="literal">def(...)</tt> function will
automatically add all the foo variants for us:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">def</span><span class="special">(</span><span class="string">"foo"</span><span class="special">,</span><span class="identifier"> foo</span><span class="special">,</span><span class="identifier"> foo_overloads</span><span class="special">());</span></tt></pre>
will automatically create the thin wrappers for us. This macro will create
a class <tt class="literal">foo_overloads</tt> that can be passed on to <tt class="literal">def(...)</tt>.
The third and fourth macro argument are the minimum arguments and maximum
arguments, respectively. In our <tt class="literal">foo</tt> function the minimum
number of arguments is 1 and the maximum number of arguments is 4. The <tt class="literal">def(...)</tt>
function will automatically add all the foo variants for us:
</p>
<pre class="programlisting">
<span class="identifier">def</span><span class="special">(</span><span class="string">"foo"</span><span class="special">,</span> <span class="identifier">foo</span><span class="special">,</span> <span class="identifier">foo_overloads</span><span class="special">());</span>
</pre>
<a name="default_arguments.boost_python_member_function_overloads"></a><h2>
<a name="id451995"></a>BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</h2>
<a name="id452863"></a>
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS
</h2>
<p>
Objects here, objects there, objects here there everywhere. More frequently
than anything else, we need to expose member functions of our classes to
Python. Then again, we have the same inconveniences as before when default
arguments or overloads with a common sequence of initial arguments come
into play. Another macro is provided to make this a breeze.</p>
Objects here, objects there, objects here there everywhere. More frequently
than anything else, we need to expose member functions of our classes to
Python. Then again, we have the same inconveniences as before when default
arguments or overloads with a common sequence of initial arguments come into
play. Another macro is provided to make this a breeze.
</p>
<p>
Like <tt class="literal">BOOST_PYTHON_FUNCTION_OVERLOADS</tt>,
<tt class="literal">BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</tt> may be used to automatically create
the thin wrappers for wrapping member functions. Let's have an example:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">struct</span><span class="identifier"> george</span><span class="special">
{</span><span class="keyword">
void</span><span class="identifier">
wack_em</span><span class="special">(</span><span class="keyword">int</span><span class="identifier"> a</span><span class="special">,</span><span class="keyword"> int</span><span class="identifier"> b</span><span class="special"> =</span><span class="number"> 0</span><span class="special">,</span><span class="keyword"> char</span><span class="identifier"> c</span><span class="special"> =</span><span class="char"> 'x'</span><span class="special">)</span><span class="special">
{</span><span class="comment">
/*...*/</span><span class="special">
}</span><span class="special">
};</span></tt></pre>
Like <tt class="literal">BOOST_PYTHON_FUNCTION_OVERLOADS</tt>, <tt class="literal">BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</tt>
may be used to automatically create the thin wrappers for wrapping member
functions. Let's have an example:
</p>
<pre class="programlisting">
<span class="keyword">struct</span> <span class="identifier">george</span>
<span class="special">{</span>
<span class="keyword">void</span>
<span class="identifier">wack_em</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">a</span><span class="special">,</span> <span class="keyword">int</span> <span class="identifier">b</span> <span class="special">=</span> <span class="number">0</span><span class="special">,</span> <span class="keyword">char</span> <span class="identifier">c</span> <span class="special">=</span> <span class="char">'x'</span><span class="special">)</span>
<span class="special">{</span>
<span class="comment">/*...*/</span>
<span class="special">}</span>
<span class="special">};</span>
</pre>
<p>
The macro invocation:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</span><span class="special">(</span><span class="identifier">george_overloads</span><span class="special">,</span><span class="identifier"> wack_em</span><span class="special">,</span><span class="number"> 1</span><span class="special">,</span><span class="number"> 3</span><span class="special">)</span></tt></pre>
The macro invocation:
</p>
<pre class="programlisting">
<span class="identifier">BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</span><span class="special">(</span><span class="identifier">george_overloads</span><span class="special">,</span> <span class="identifier">wack_em</span><span class="special">,</span> <span class="number">1</span><span class="special">,</span> <span class="number">3</span><span class="special">)</span>
</pre>
<p>
will generate a set of thin wrappers for george's <tt class="literal">wack_em</tt> member function
accepting a minimum of 1 and a maximum of 3 arguments (i.e. the third and
fourth macro argument). The thin wrappers are all enclosed in a class named
<tt class="literal">george_overloads</tt> that can then be used as an argument to <tt class="literal">def(...)</tt>:</p>
<pre class="programlisting"><tt class="literal"><span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"wack_em"</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">george</span><span class="special">::</span><span class="identifier">wack_em</span><span class="special">,</span><span class="identifier"> george_overloads</span><span class="special">());</span></tt></pre>
will generate a set of thin wrappers for george's <tt class="literal">wack_em</tt>
member function accepting a minimum of 1 and a maximum of 3 arguments (i.e.
the third and fourth macro argument). The thin wrappers are all enclosed
in a class named <tt class="literal">george_overloads</tt> that can then be used
as an argument to <tt class="literal">def(...)</tt>:
</p>
<pre class="programlisting">
<span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"wack_em"</span><span class="special">,</span> <span class="special">&amp;</span><span class="identifier">george</span><span class="special">::</span><span class="identifier">wack_em</span><span class="special">,</span> <span class="identifier">george_overloads</span><span class="special">());</span>
</pre>
<p>
See the <a href="../../../../v2/overloads.html#BOOST_PYTHON_FUNCTION_OVERLOADS-spec" target="_top">overloads reference</a>
for details.</p>
See the <a href="../../../../v2/overloads.html#BOOST_PYTHON_FUNCTION_OVERLOADS-spec" target="_top">overloads
reference</a> for details.
</p>
<a name="default_arguments.init_and_optional"></a><h2>
<a name="id452323"></a>init and optional</h2>
<a name="id453212"></a>
init and optional
</h2>
<p>
A similar facility is provided for class constructors, again, with
default arguments or a sequence of overloads. Remember <tt class="literal">init&lt;...&gt;</tt>? For example,
given a class X with a constructor:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">struct</span><span class="identifier"> X</span><span class="special">
{</span><span class="identifier">
X</span><span class="special">(</span><span class="keyword">int</span><span class="identifier"> a</span><span class="special">,</span><span class="keyword"> char</span><span class="identifier"> b</span><span class="special"> =</span><span class="char"> 'D'</span><span class="special">,</span><span class="identifier"> std</span><span class="special">::</span><span class="identifier">string</span><span class="identifier"> c</span><span class="special"> =</span><span class="string"> "constructor"</span><span class="special">,</span><span class="keyword"> double</span><span class="identifier"> d</span><span class="special"> =</span><span class="number"> 0.0</span><span class="special">);</span><span class="comment">
/*...*/</span><span class="special">
}</span></tt></pre>
A similar facility is provided for class constructors, again, with default
arguments or a sequence of overloads. Remember <tt class="literal">init&lt;...&gt;</tt>?
For example, given a class X with a constructor:
</p>
<pre class="programlisting">
<span class="keyword">struct</span> <span class="identifier">X</span>
<span class="special">{</span>
<span class="identifier">X</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">a</span><span class="special">,</span> <span class="keyword">char</span> <span class="identifier">b</span> <span class="special">=</span> <span class="char">'D'</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">c</span> <span class="special">=</span> <span class="string">"constructor"</span><span class="special">,</span> <span class="keyword">double</span> <span class="identifier">d</span> <span class="special">=</span> <span class="number">0.0</span><span class="special">);</span>
<span class="comment">/*...*/</span>
<span class="special">}</span>
</pre>
<p>
You can easily add this constructor to Boost.Python in one shot:</p>
<pre class="programlisting"><tt class="literal"><span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">init</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">,</span><span class="identifier"> optional</span><span class="special">&lt;</span><span class="keyword">char</span><span class="special">,</span><span class="identifier"> std</span><span class="special">::</span><span class="identifier">string</span><span class="special">,</span><span class="keyword"> double</span><span class="special">&gt;</span><span class="special"> &gt;())</span></tt></pre>
You can easily add this constructor to Boost.Python in one shot:
</p>
<pre class="programlisting">
<span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">init</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">,</span> <span class="identifier">optional</span><span class="special">&lt;</span><span class="keyword">char</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">,</span> <span class="keyword">double</span><span class="special">&gt;</span> <span class="special">&gt;())</span>
</pre>
<p>
Notice the use of <tt class="literal">init&lt;...&gt;</tt> and <tt class="literal">optional&lt;...&gt;</tt> to signify the default
(optional arguments).</p>
Notice the use of <tt class="literal">init&lt;...&gt;</tt> and <tt class="literal">optional&lt;...&gt;</tt>
to signify the default (optional arguments).
</p>
</div>
<div class="section" lang="en">
<div class="titlepage"><div><div><h3 class="title">
<a name="python.auto_overloading"></a>Auto-Overloading</h3></div></div></div>
<p>
It was mentioned in passing in the previous section that
<tt class="literal">BOOST_PYTHON_FUNCTION_OVERLOADS</tt> and <tt class="literal">BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</tt>
can also be used for overloaded functions and member functions with a
common sequence of initial arguments. Here is an example:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">void</span><span class="identifier"> foo</span><span class="special">()</span><span class="special">
{</span><span class="comment">
/*...*/</span><span class="special">
}</span><span class="keyword">
Auto-OverloadingIt was mentioned in passing in the previous section that
<tt class="literal">BOOST_PYTHON_FUNCTION_OVERLOADS</tt> and <tt class="literal">BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</tt>
can also be used for overloaded functions and member functions with a common
sequence of initial arguments. Here is an example:
</p>
<pre class="programlisting">
<span class="keyword">void</span> <span class="identifier">foo</span><span class="special">()</span>
<span class="special">{</span>
<span class="comment">/*...*/</span>
<span class="special">}</span>
void</span><span class="identifier"> foo</span><span class="special">(</span><span class="keyword">bool</span><span class="identifier"> a</span><span class="special">)</span><span class="special">
{</span><span class="comment">
/*...*/</span><span class="special">
}</span><span class="keyword">
<span class="keyword">void</span> <span class="identifier">foo</span><span class="special">(</span><span class="keyword">bool</span> <span class="identifier">a</span><span class="special">)</span>
<span class="special">{</span>
<span class="comment">/*...*/</span>
<span class="special">}</span>
void</span><span class="identifier"> foo</span><span class="special">(</span><span class="keyword">bool</span><span class="identifier"> a</span><span class="special">,</span><span class="keyword"> int</span><span class="identifier"> b</span><span class="special">)</span><span class="special">
{</span><span class="comment">
/*...*/</span><span class="special">
}</span><span class="keyword">
<span class="keyword">void</span> <span class="identifier">foo</span><span class="special">(</span><span class="keyword">bool</span> <span class="identifier">a</span><span class="special">,</span> <span class="keyword">int</span> <span class="identifier">b</span><span class="special">)</span>
<span class="special">{</span>
<span class="comment">/*...*/</span>
<span class="special">}</span>
void</span><span class="identifier"> foo</span><span class="special">(</span><span class="keyword">bool</span><span class="identifier"> a</span><span class="special">,</span><span class="keyword"> int</span><span class="identifier"> b</span><span class="special">,</span><span class="keyword"> char</span><span class="identifier"> c</span><span class="special">)</span><span class="special">
{</span><span class="comment">
/*...*/</span><span class="special">
}</span></tt></pre>
<span class="keyword">void</span> <span class="identifier">foo</span><span class="special">(</span><span class="keyword">bool</span> <span class="identifier">a</span><span class="special">,</span> <span class="keyword">int</span> <span class="identifier">b</span><span class="special">,</span> <span class="keyword">char</span> <span class="identifier">c</span><span class="special">)</span>
<span class="special">{</span>
<span class="comment">/*...*/</span>
<span class="special">}</span>
</pre>
<p>
Like in the previous section, we can generate thin wrappers for these
overloaded functions in one-shot:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">BOOST_PYTHON_FUNCTION_OVERLOADS</span><span class="special">(</span><span class="identifier">foo_overloads</span><span class="special">,</span><span class="identifier"> foo</span><span class="special">,</span><span class="number"> 0</span><span class="special">,</span><span class="number"> 3</span><span class="special">)</span></tt></pre>
Like in the previous section, we can generate thin wrappers for these overloaded
functions in one-shot:
</p>
<pre class="programlisting">
<span class="identifier">BOOST_PYTHON_FUNCTION_OVERLOADS</span><span class="special">(</span><span class="identifier">foo_overloads</span><span class="special">,</span> <span class="identifier">foo</span><span class="special">,</span> <span class="number">0</span><span class="special">,</span> <span class="number">3</span><span class="special">)</span>
</pre>
<p>
Then...</p>
<pre class="programlisting"><tt class="literal"><span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"foo"</span><span class="special">,</span><span class="identifier"> foo</span><span class="special">,</span><span class="identifier"> foo_overloads</span><span class="special">());</span></tt></pre>
Then...
</p>
<pre class="programlisting">
<span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"foo"</span><span class="special">,</span> <span class="identifier">foo</span><span class="special">,</span> <span class="identifier">foo_overloads</span><span class="special">());</span>
</pre>
<p>
Notice though that we have a situation now where we have a minimum of zero
(0) arguments and a maximum of 3 arguments.</p>
Notice though that we have a situation now where we have a minimum of zero
(0) arguments and a maximum of 3 arguments.
</p>
<a name="auto_overloading.manual_wrapping"></a><h2>
<a name="id452969"></a>Manual Wrapping</h2>
<a name="id453917"></a>
Manual Wrapping
</h2>
<p>
It is important to emphasize however that <span class="bold"><b>the overloaded functions must
have a common sequence of initial arguments</b></span>. Otherwise, our scheme above
will not work. If this is not the case, we have to wrap our functions
<a href="functions.html#python.overloading" title="Overloading">manually</a>.</p>
It is important to emphasize however that <span class="bold"><b>the overloaded
functions must have a common sequence of initial arguments</b></span>. Otherwise,
our scheme above will not work. If this is not the case, we have to wrap
our functions <a href="functions.html#python.overloading" title="Overloading">manually</a>.
</p>
<p>
Actually, we can mix and match manual wrapping of overloaded functions and
automatic wrapping through <tt class="literal">BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</tt> and
its sister, <tt class="literal">BOOST_PYTHON_FUNCTION_OVERLOADS</tt>. Following up on our example
presented in the section <a href="functions.html#python.overloading" title="Overloading">on overloading</a>, since the
first 4 overload functins have a common sequence of initial arguments, we
can use <tt class="literal">BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</tt> to automatically wrap the
first three of the <tt class="literal">def</tt>s and manually wrap just the last. Here's
how we'll do this:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</span><span class="special">(</span><span class="identifier">xf_overloads</span><span class="special">,</span><span class="identifier"> f</span><span class="special">,</span><span class="number"> 1</span><span class="special">,</span><span class="number"> 4</span><span class="special">)</span></tt></pre>
Actually, we can mix and match manual wrapping of overloaded functions and
automatic wrapping through <tt class="literal">BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</tt>
and its sister, <tt class="literal">BOOST_PYTHON_FUNCTION_OVERLOADS</tt>. Following
up on our example presented in the section <a href="functions.html#python.overloading" title="Overloading">on
overloading</a>, since the first 4 overload functins have a common sequence
of initial arguments, we can use <tt class="literal">BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</tt>
to automatically wrap the first three of the <tt class="literal">def</tt>s and
manually wrap just the last. Here's how we'll do this:
</p>
<pre class="programlisting">
<span class="identifier">BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</span><span class="special">(</span><span class="identifier">xf_overloads</span><span class="special">,</span> <span class="identifier">f</span><span class="special">,</span> <span class="number">1</span><span class="special">,</span> <span class="number">4</span><span class="special">)</span>
</pre>
<p>
Create a member function pointers as above for both X::f overloads:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">bool</span><span class="special"> (</span><span class="identifier">X</span><span class="special">::*</span><span class="identifier">fx1</span><span class="special">)(</span><span class="keyword">int</span><span class="special">,</span><span class="keyword"> double</span><span class="special">,</span><span class="keyword"> char</span><span class="special">)</span><span class="special"> =</span><span class="special"> &amp;</span><span class="identifier">X</span><span class="special">::</span><span class="identifier">f</span><span class="special">;</span><span class="keyword">
int</span><span class="special"> (</span><span class="identifier">X</span><span class="special">::*</span><span class="identifier">fx2</span><span class="special">)(</span><span class="keyword">int</span><span class="special">,</span><span class="keyword"> int</span><span class="special">,</span><span class="keyword"> int</span><span class="special">)</span><span class="special"> =</span><span class="special"> &amp;</span><span class="identifier">X</span><span class="special">::</span><span class="identifier">f</span><span class="special">;</span></tt></pre>
Create a member function pointers as above for both X::f overloads:
</p>
<pre class="programlisting">
<span class="keyword">bool</span> <span class="special">(</span><span class="identifier">X</span><span class="special">::*</span><span class="identifier">fx1</span><span class="special">)(</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">double</span><span class="special">,</span> <span class="keyword">char</span><span class="special">)</span> <span class="special">=</span> <span class="special">&amp;</span><span class="identifier">X</span><span class="special">::</span><span class="identifier">f</span><span class="special">;</span>
<span class="keyword">int</span> <span class="special">(</span><span class="identifier">X</span><span class="special">::*</span><span class="identifier">fx2</span><span class="special">)(</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">int</span><span class="special">,</span> <span class="keyword">int</span><span class="special">)</span> <span class="special">=</span> <span class="special">&amp;</span><span class="identifier">X</span><span class="special">::</span><span class="identifier">f</span><span class="special">;</span>
</pre>
<p>
Then...</p>
<pre class="programlisting"><tt class="literal"><span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span><span class="identifier"> fx1</span><span class="special">,</span><span class="identifier"> xf_overloads</span><span class="special">());</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span><span class="identifier"> fx2</span><span class="special">)</span></tt></pre>
Then...
</p>
<pre class="programlisting">
<span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span> <span class="identifier">fx1</span><span class="special">,</span> <span class="identifier">xf_overloads</span><span class="special">());</span>
<span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span> <span class="identifier">fx2</span><span class="special">)</span>
</pre>
</div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><small>Copyright © 2002-2005 Joel de Guzman, David Abrahams</small></td>
<td align="right"><small>Copyright © 2002-2005 Joel
de Guzman, David Abrahams</small></td>
</tr></table>
<hr>
<div class="spirit-nav">

View File

@ -25,79 +25,88 @@
<div class="section" lang="en">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="python.hello"></a> Building Hello World</h2></div></div></div>
<a name="hello.from_start_to_finish"></a><h2>
<a name="id374047"></a>From Start To Finish</h2>
<a name="hello._building_hello_worldfrom_start_to_finish"></a><h2>
<a name="id442456"></a>
Building Hello WorldFrom Start To Finish
</h2>
<p>
Now the first thing you'd want to do is to build the Hello World module and
try it for yourself in Python. In this section, we shall outline the steps
necessary to achieve that. We shall use the build tool that comes bundled
with every boost distribution: <span class="bold"><b>bjam</b></span>.</p>
Now the first thing you'd want to do is to build the Hello World module and
try it for yourself in Python. In this section, we shall outline the steps
necessary to achieve that. We shall use the build tool that comes bundled with
every boost distribution: <span class="bold"><b>bjam</b></span>.
</p>
<div class="informaltable"><table class="table">
<colgroup><col></colgroup>
<tbody><tr><td class="blurb">
<span class="inlinemediaobject"><img src="../images/note.png"></span><span class="bold"><b>Building without bjam</b></span><br><br>
Besides bjam, there are of course other ways to get your module built.
What's written here should not be taken as "the one and only way".
There are of course other build tools apart from <tt class="literal">bjam</tt>.<br><br>
Take note however that the preferred build tool for Boost.Python is bjam.
There are so many ways to set up the build incorrectly. Experience shows
that 90% of the "I can't build Boost.Python" problems come from people
who had to use a different tool.
</td></tr></tbody>
<span class="inlinemediaobject"><img src="../images/note.png"></span> <span class="bold"><b>Building without bjam</b></span><br><br> Besides bjam,
there are of course other ways to get your module built. What's written
here should not be taken as "the one and only way". There are
of course other build tools apart from <tt class="literal">bjam</tt>.<br><br> Take note however that the preferred build tool for Boost.Python
is bjam. There are so many ways to set up the build incorrectly. Experience
shows that 90% of the "I can't build Boost.Python" problems
come from people who had to use a different tool. </td></tr></tbody>
</table></div>
<p>
We shall skip over the details. Our objective will be to simply create the
hello world module and run it in Python. For a complete reference to
building Boost.Python, check out: <a href="../../../../building.html" target="_top">building.html</a>.
After this brief <span class="emphasis"><em>bjam</em></span> tutorial, we should have built two DLLs:</p>
We shall skip over the details. Our objective will be to simply create the
hello world module and run it in Python. For a complete reference to building
Boost.Python, check out: <a href="../../../../building.html" target="_top">building.html</a>.
After this brief <span class="emphasis"><em>bjam</em></span> tutorial, we should have built two
DLLs:
</p>
<div class="itemizedlist"><ul type="disc">
<li>
boost_python.dll
</li>
boost_python.dll
</li>
<li>
hello.pyd
</li>
hello.pyd
</li>
</ul></div>
<p>
if you are on Windows, and</p>
if you are on Windows, and
</p>
<div class="itemizedlist"><ul type="disc">
<li>
libboost_python.so
</li>
libboost_python.so
</li>
<li>
hello.so
</li>
hello.so
</li>
</ul></div>
<p>
if you are on Unix.</p>
if you are on Unix.
</p>
<p>
The tutorial example can be found in the directory:
<tt class="literal">libs/python/example/tutorial</tt>. There, you can find:</p>
The tutorial example can be found in the directory: <tt class="literal">libs/python/example/tutorial</tt>.
There, you can find:
</p>
<div class="itemizedlist"><ul type="disc">
<li>
hello.cpp
</li>
hello.cpp
</li>
<li>
Jamfile
</li>
Jamfile
</li>
</ul></div>
<p>
The <tt class="literal">hello.cpp</tt> file is our C++ hello world example. The <tt class="literal">Jamfile</tt> is a
minimalist <span class="emphasis"><em>bjam</em></span> script that builds the DLLs for us.</p>
The <tt class="literal">hello.cpp</tt> file is our C++ hello world example. The
<tt class="literal">Jamfile</tt> is a minimalist <span class="emphasis"><em>bjam</em></span> script
that builds the DLLs for us.
</p>
<p>
Before anything else, you should have the bjam executable in your boost
directory or somewhere in your path such that <tt class="literal">bjam</tt> can be executed in
the command line. Pre-built Boost.Jam executables are available for most
platforms. The complete list of Bjam executables can be found
<a href="http://sourceforge.net/project/showfiles.php?group_id=7586" target="_top">here</a>.</p>
Before anything else, you should have the bjam executable in your boost directory
or somewhere in your path such that <tt class="literal">bjam</tt> can be executed
in the command line. Pre-built Boost.Jam executables are available for most
platforms. The complete list of Bjam executables can be found <a href="http://sourceforge.net/project/showfiles.php?group_id=7586" target="_top">here</a>.
</p>
<a name="hello.let_s_jam_"></a><h2>
<a name="id372653"></a>Let's Jam!</h2>
<a name="id373799"></a>
Let's Jam!
</h2>
<p><span class="inlinemediaobject"><img src="../images/jam.png"></span></p>
<p>
Here is our minimalist Jamfile:</p>
<pre class="programlisting"><tt class="literal"># This is the top of our own project tree
Here is our minimalist Jamfile:
</p>
<pre class="programlisting"># This is the top of our own project tree
project-root ;
import python ;
@ -107,85 +116,106 @@ extension hello # Declare a Python extension called hello
# requirements and dependencies for Boost.Python extensions
&lt;template&gt;@boost/libs/python/build/extension
;
</tt></pre>
</pre>
<p>
First, we need to specify our location. You may place your project anywhere.
<tt class="literal">project-root</tt> allows you to do that.</p>
<pre class="programlisting"><tt class="literal">project-root ;
</tt></pre>
First, we need to specify our location. You may place your project anywhere.
<tt class="literal">project-root</tt> allows you to do that.
</p>
<pre class="programlisting">project-root ;
</pre>
<p>
By doing so, you'll need a Jamrules file. Simply copy the one in the
<a href="../../../../../example/tutorial/Jamrules" target="_top">example/tutorial directory</a> and tweak
the <tt class="literal">path-global BOOST_ROOT</tt> to where your boost root directory is. The file
has <a href="../../../../../example/tutorial/Jamrules" target="_top">detailed instructions</a> you can follow.</p>
By doing so, you'll need a Jamrules file. Simply copy the one in the <a href="../../../../../example/tutorial/Jamrules" target="_top">example/tutorial directory</a>
and tweak the <tt class="literal">path-global BOOST_ROOT</tt> to where your boost
root directory is. The file has <a href="../../../../../example/tutorial/Jamrules" target="_top">detailed
instructions</a> you can follow.
</p>
<p>
Then we will import the definitions needed by Python modules:</p>
<pre class="programlisting"><tt class="literal">import python ;
</tt></pre>
Then we will import the definitions needed by Python modules:
</p>
<pre class="programlisting">import python ;
</pre>
<p>
Finally we declare our <tt class="literal">hello</tt> extension:</p>
<pre class="programlisting"><tt class="literal">extension hello # Declare a Python extension called hello
Finally we declare our <tt class="literal">hello</tt> extension:
</p>
<pre class="programlisting">extension hello # Declare a Python extension called hello
: hello.cpp # source
# requirements and dependencies for Boost.Python extensions
&lt;template&gt;@boost/libs/python/build/extension
;
</tt></pre>
</pre>
<p>
The last part tells BJam that we are depending on the Boost Python Library.</p>
The last part tells BJam that we are depending on the Boost Python Library.
</p>
<a name="hello.running_bjam"></a><h2>
<a name="id372775"></a>Running bjam</h2>
<p><span class="emphasis"><em>bjam</em></span> is run using your operating system's command line interpreter.</p>
<div class="blockquote"><blockquote class="blockquote"><p>Start it up.</p></blockquote></div>
<a name="id373910"></a>
Running bjam
</h2>
<p><span class="emphasis"><em>bjam</em></span> is run using your operating system's command line
interpreter.
</p>
<div class="blockquote"><blockquote class="blockquote"><p>
Start it up.
</p></blockquote></div>
<p>
Make sure that the environment is set so that we can invoke the C++
compiler. With MSVC, that would mean running the <tt class="literal">Vcvars32.bat</tt> batch
file. For instance:</p>
<pre class="programlisting"><tt class="literal">C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\Tools\vsvars32.bat
</tt></pre>
Make sure that the environment is set so that we can invoke the C++ compiler.
With MSVC, that would mean running the <tt class="literal">Vcvars32.bat</tt> batch
file. For instance:
</p>
<pre class="programlisting">C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\Tools\vsvars32.bat
</pre>
<p>
Some environment variables will have to be setup for proper building of our
Python modules. Example:</p>
<pre class="programlisting"><tt class="literal">set PYTHON_ROOT=c:/dev/tools/python
Some environment variables will have to be setup for proper building of our
Python modules. Example:
</p>
<pre class="programlisting">set PYTHON_ROOT=c:/dev/tools/python
set PYTHON_VERSION=2.2
</tt></pre>
</pre>
<p>
The above assumes that the Python installation is in <tt class="literal">c:/dev/tools/python</tt>
and that we are using Python version 2.2. You'll have to tweak these
appropriately.</p>
The above assumes that the Python installation is in <tt class="literal">c:/dev/tools/python</tt>
and that we are using Python version 2.2. You'll have to tweak these appropriately.
</p>
<div class="informaltable"><table class="table">
<colgroup><col></colgroup>
<tbody><tr><td class="blurb">
<span class="inlinemediaobject"><img src="../images/tip.png"></span> Be sure not to include a third number, e.g. <span class="bold"><b>not</b></span> "2.2.1",
even if that's the version you have.</td></tr></tbody>
<span class="inlinemediaobject"><img src="../images/tip.png"></span>
Be sure not to include a third number, e.g. <span class="bold"><b>not</b></span>
"2.2.1", even if that's the version you have.</td></tr></tbody>
</table></div>
<p>
Take note that you may also do that through the Jamrules file we put in
our project as detailed above. The file
has <a href="../../../../../example/tutorial/Jamrules" target="_top">detailed instructions</a> you
can follow.</p>
Take note that you may also do that through the Jamrules file we put in our
project as detailed above. The file has <a href="../../../../../example/tutorial/Jamrules" target="_top">detailed
instructions</a> you can follow.
</p>
<p>
Now we are ready... Be sure to <tt class="literal">cd</tt> to <tt class="literal">libs/python/example/tutorial</tt>
where the tutorial <tt class="literal">"hello.cpp"</tt> and the <tt class="literal">"Jamfile"</tt> is situated.</p>
Now we are ready... Be sure to <tt class="literal">cd</tt> to <tt class="literal">libs/python/example/tutorial</tt>
where the tutorial <tt class="literal">"hello.cpp"</tt> and the <tt class="literal">"Jamfile"</tt>
is situated.
</p>
<p>
Finally:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">bjam</span><span class="special"> -</span><span class="identifier">sTOOLS</span><span class="special">=</span><span class="identifier">vc</span><span class="special">-</span><span class="number">7</span><span class="identifier">_1</span></tt></pre>
Finally:
</p>
<pre class="programlisting">
<span class="identifier">bjam</span> <span class="special">-</span><span class="identifier">sTOOLS</span><span class="special">=</span><span class="identifier">vc</span><span class="special">-</span><span class="number">7</span><span class="identifier">_1</span>
</pre>
<p>
We are again assuming that we are using Microsoft Visual C++ version 7.1. If
not, then you will have to specify the appropriate tool. See
<a href="../../../../../../../tools/build/index.html" target="_top">Building Boost Libraries</a> for
further details.</p>
We are again assuming that we are using Microsoft Visual C++ version 7.1. If
not, then you will have to specify the appropriate tool. See <a href="../../../../../../../tools/build/index.html" target="_top">Building
Boost Libraries</a> for further details.
</p>
<p>
It should be building now:</p>
<pre class="programlisting"><tt class="literal">cd C:\dev\boost\libs\python\example\tutorial
It should be building now:
</p>
<pre class="programlisting">cd C:\dev\boost\libs\python\example\tutorial
bjam -sTOOLS=msvc
...patience...
...found 1703 targets...
...updating 40 targets...
</tt></pre>
</pre>
<p>
And so on... Finally:</p>
<pre class="programlisting"><tt class="literal">Creating library bin\boost\libs\python\build\boost_python.dll\vc-7_1\debug\th
And so on... Finally:
</p>
<pre class="programlisting">Creating library bin\boost\libs\python\build\boost_python.dll\vc-7_1\debug\th
reading-multi\boost_python.lib and object bin\boost\libs\python\build\boost_pyth
on.dll\vc-7_1\debug\threading-multi\boost_python.exp
vc-C++ bin\tutorial\hello.pyd\vc-7_1\debug\threading-multi\hello.obj
@ -195,45 +225,54 @@ al\hello.pyd\vc-7_1\debug\threading-multi\hello.lib
Creating library bin\tutorial\hello.pyd\vc-7_1\debug\threading-multi\hello.li
b and object bin\tutorial\hello.pyd\vc-7_1\debug\threading-multi\hello.exp
...updated 31 targets...
</tt></pre>
</pre>
<p>
If all is well, you should now have:</p>
If all is well, you should now have:
</p>
<div class="itemizedlist"><ul type="disc">
<li>
boost_python.dll
</li>
boost_python.dll
</li>
<li>
hello.pyd
</li>
hello.pyd
</li>
</ul></div>
<p>
if you are on Windows, and</p>
if you are on Windows, and
</p>
<div class="itemizedlist"><ul type="disc">
<li>
libboost_python.so
</li>
libboost_python.so
</li>
<li>
hello.so
</li>
hello.so
</li>
</ul></div>
<p>
if you are on Unix.</p>
<p><tt class="literal">boost_python.dll</tt> and <tt class="literal">hello.pyd</tt> can be found somewhere in your project's
<tt class="literal">bin</tt> directory. After a successful build, you can just link in these DLLs with
the Python interpreter. In Windows for example, you can simply put these libraries
inside the directory where the Python executable is.</p>
if you are on Unix.
</p>
<p><tt class="literal">boost_python.dll</tt> and <tt class="literal">hello.pyd</tt> can be
found somewhere in your project's <tt class="literal">bin</tt> directory. After a
successful build, you can just link in these DLLs with the Python interpreter.
In Windows for example, you can simply put these libraries inside the directory
where the Python executable is.
</p>
<p>
You may now fire up Python and run our hello module:</p>
You may now fire up Python and run our hello module:
</p>
<p></p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="keyword"> import</span><span class="identifier"> hello</span><span class="special">
&gt;&gt;&gt;</span><span class="keyword"> print</span><span class="identifier"> hello</span><span class="special">.</span><span class="identifier">greet</span><span class="special">()</span><span class="identifier">
hello</span><span class="special">,</span><span class="identifier"> world</span></tt></pre>
<pre class="programlisting">
<span class="special">&gt;&gt;&gt;</span> <span class="keyword">import</span> <span class="identifier">hello</span>
<span class="special">&gt;&gt;&gt;</span> <span class="keyword">print</span> <span class="identifier">hello</span><span class="special">.</span><span class="identifier">greet</span><span class="special">()</span>
<span class="identifier">hello</span><span class="special">,</span> <span class="identifier">world</span>
</pre>
<p></p>
<div class="blockquote"><blockquote class="blockquote"><p><span class="bold"><b>There you go... Have fun!</b></span></p></blockquote></div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><small>Copyright © 2002-2005 Joel de Guzman, David Abrahams</small></td>
<td align="right"><small>Copyright © 2002-2005 Joel
de Guzman, David Abrahams</small></td>
</tr></table>
<hr>
<div class="spirit-nav">

View File

@ -26,104 +26,156 @@
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="python.iterators"></a>Iterators</h2></div></div></div>
<p>
In C++, and STL in particular, we see iterators everywhere. Python also has
iterators, but these are two very different beasts.</p>
IteratorsIn C++, and STL in particular, we see iterators everywhere. Python
also has iterators, but these are two very different beasts.
</p>
<p><span class="bold"><b>C++ iterators:</b></span></p>
<div class="itemizedlist"><ul type="disc">
<li>
C++ has 5 type categories (random-access, bidirectional, forward, input, output)
</li>
C++ has 5 type categories (random-access, bidirectional, forward, input,
output)
</li>
<li>
There are 2 Operation categories: reposition, access
</li>
There are 2 Operation categories: reposition, access
</li>
<li>
A pair of iterators is needed to represent a (first/last) range.
</li>
A pair of iterators is needed to represent a (first/last) range.
</li>
</ul></div>
<p><span class="bold"><b>Python Iterators:</b></span></p>
<div class="itemizedlist"><ul type="disc">
<li>
1 category (forward)
</li>
1 category (forward)
</li>
<li>
1 operation category (next())
</li>
1 operation category (next())
</li>
<li>
Raises StopIteration exception at end
</li>
Raises StopIteration exception at end
</li>
</ul></div>
<p>
The typical Python iteration protocol: <tt class="literal"><span class="bold"><b>for y in x...</b></span></tt> is as follows:</p>
The typical Python iteration protocol: <tt class="literal"><span class="bold"><b>for y
in x...</b></span></tt> is as follows:
</p>
<p></p>
<pre class="programlisting"><tt class="literal"><span class="identifier">iter</span><span class="special"> =</span><span class="identifier"> x</span><span class="special">.</span><span class="identifier">__iter__</span><span class="special">()</span><span class="comment"> # get iterator
</span><span class="keyword">try</span><span class="special">:</span><span class="keyword">
while</span><span class="number"> 1</span><span class="special">:</span><span class="identifier">
y</span><span class="special"> =</span><span class="identifier"> iter</span><span class="special">.</span><span class="identifier">next</span><span class="special">()</span><span class="comment"> # get each item
</span><span class="special"> ...</span><span class="comment"> # process y
</span><span class="keyword">except</span><span class="identifier"> StopIteration</span><span class="special">:</span><span class="keyword"> pass</span><span class="comment"> # iterator exhausted
</span></tt></pre>
<pre class="programlisting">
<span class="identifier">iter</span> <span class="special">=</span> <span class="identifier">x</span><span class="special">.</span><span class="identifier">__iter__</span><span class="special">()</span> <span class="comment"># get iterator
</span><span class="keyword">try</span><span class="special">:</span>
<span class="keyword">while</span> <span class="number">1</span><span class="special">:</span>
<span class="identifier">y</span> <span class="special">=</span> <span class="identifier">iter</span><span class="special">.</span><span class="identifier">next</span><span class="special">()</span> <span class="comment"># get each item
</span> <span class="special">...</span> <span class="comment"># process y
</span><span class="keyword">except</span> <span class="identifier">StopIteration</span><span class="special">:</span> <span class="keyword">pass</span> <span class="comment"># iterator exhausted
</span></pre>
<p>
Boost.Python provides some mechanisms to make C++ iterators play along
nicely as Python iterators. What we need to do is to produce
appropriate <tt class="computeroutput"><span class="identifier">__iter__</span></tt> function from C++ iterators that is compatible
with the Python iteration protocol. For example:</p>
Boost.Python provides some mechanisms to make C++ iterators play along nicely
as Python iterators. What we need to do is to produce appropriate <tt class="computeroutput"><span class="identifier">__iter__</span></tt> function from C++ iterators that
is compatible with the Python iteration protocol. For example:
</p>
<p></p>
<pre class="programlisting"><tt class="literal"><span class="identifier">object</span><span class="identifier"> get_iterator</span><span class="special"> =</span><span class="identifier"> iterator</span><span class="special">&lt;</span><span class="identifier">vector</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;</span><span class="special"> &gt;();</span><span class="identifier">
object</span><span class="identifier"> iter</span><span class="special"> =</span><span class="identifier"> get_iterator</span><span class="special">(</span><span class="identifier">v</span><span class="special">);</span><span class="identifier">
object</span><span class="identifier"> first</span><span class="special"> =</span><span class="identifier"> iter</span><span class="special">.</span><span class="identifier">next</span><span class="special">();</span></tt></pre>
<pre class="programlisting">
<span class="identifier">object</span> <span class="identifier">get_iterator</span> <span class="special">=</span> <span class="identifier">iterator</span><span class="special">&lt;</span><span class="identifier">vector</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;</span> <span class="special">&gt;();</span>
<span class="identifier">object</span> <span class="identifier">iter</span> <span class="special">=</span> <span class="identifier">get_iterator</span><span class="special">(</span><span class="identifier">v</span><span class="special">);</span>
<span class="identifier">object</span> <span class="identifier">first</span> <span class="special">=</span> <span class="identifier">iter</span><span class="special">.</span><span class="identifier">next</span><span class="special">();</span>
</pre>
<p>
Or for use in class_&lt;&gt;:</p>
<pre class="programlisting"><tt class="literal"><span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"__iter__"</span><span class="special">,</span><span class="identifier"> iterator</span><span class="special">&lt;</span><span class="identifier">vector</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;</span><span class="special"> &gt;())</span></tt></pre>
Or for use in class_&lt;&gt;:
</p>
<pre class="programlisting">
<span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"__iter__"</span><span class="special">,</span> <span class="identifier">iterator</span><span class="special">&lt;</span><span class="identifier">vector</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;</span> <span class="special">&gt;())</span>
</pre>
<p><span class="bold"><b>range</b></span></p>
<p>
We can create a Python savvy iterator using the range function:</p>
We can create a Python savvy iterator using the range function:
</p>
<div class="itemizedlist"><ul type="disc">
<li>
range(start, finish)
</li>
range(start, finish)
</li>
<li>
range&lt;Policies,Target&gt;(start, finish)
</li>
range&lt;Policies,Target&gt;(start, finish)
</li>
</ul></div>
<p>
Here, start/finish may be one of:</p>
Here, start/finish may be one of:
</p>
<div class="itemizedlist"><ul type="disc">
<li>
member data pointers
</li>
member data pointers
</li>
<li>
member function pointers
</li>
member function pointers
</li>
<li>
adaptable function object (use Target parameter)
</li>
adaptable function object (use Target parameter)
</li>
</ul></div>
<p><span class="bold"><b>iterator</b></span></p>
<div class="itemizedlist"><ul type="disc"><li>
iterator&lt;T, Policies&gt;()
</li></ul></div>
iterator&lt;T, Policies&gt;()
</li></ul></div>
<p>
Given a container <tt class="literal">T</tt>, iterator is a shortcut that simply calls <tt class="literal">range</tt>
with &amp;T::begin, &amp;T::end.</p>
Given a container <tt class="literal">T</tt>, iterator is a shortcut that simply
calls <tt class="literal">range</tt> with &amp;T::begin, &amp;T::end.
</p>
<p>
Let's put this into action... Here's an example from some hypothetical
bogon Particle accelerator code:</p>
Let's put this into action... Here's an example from some hypothetical bogon
Particle accelerator code:
</p>
<p></p>
<pre class="programlisting"><tt class="literal"><span class="identifier">f</span><span class="special"> =</span><span class="identifier"> Field</span><span class="special">()</span><span class="keyword">
for</span><span class="identifier"> x</span><span class="keyword"> in</span><span class="identifier"> f</span><span class="special">.</span><span class="identifier">pions</span><span class="special">:</span><span class="identifier">
smash</span><span class="special">(</span><span class="identifier">x</span><span class="special">)</span><span class="keyword">
for</span><span class="identifier"> y</span><span class="keyword"> in</span><span class="identifier"> f</span><span class="special">.</span><span class="identifier">bogons</span><span class="special">:</span><span class="identifier">
count</span><span class="special">(</span><span class="identifier">y</span><span class="special">)</span></tt></pre>
<pre class="programlisting">
<span class="identifier">f</span> <span class="special">=</span> <span class="identifier">Field</span><span class="special">()</span>
<span class="keyword">for</span> <span class="identifier">x</span> <span class="keyword">in</span> <span class="identifier">f</span><span class="special">.</span><span class="identifier">pions</span><span class="special">:</span>
<span class="identifier">smash</span><span class="special">(</span><span class="identifier">x</span><span class="special">)</span>
<span class="keyword">for</span> <span class="identifier">y</span> <span class="keyword">in</span> <span class="identifier">f</span><span class="special">.</span><span class="identifier">bogons</span><span class="special">:</span>
<span class="identifier">count</span><span class="special">(</span><span class="identifier">y</span><span class="special">)</span>
</pre>
<p>
Now, our C++ Wrapper:</p>
Now, our C++ Wrapper:
</p>
<p></p>
<pre class="programlisting"><tt class="literal"><span class="identifier">class_</span><span class="special">&lt;</span><span class="identifier">F</span><span class="special">&gt;(</span><span class="string">"Field"</span><span class="special">)</span><span class="special">
.</span><span class="identifier">property</span><span class="special">(</span><span class="string">"pions"</span><span class="special">,</span><span class="identifier"> range</span><span class="special">(&amp;</span><span class="identifier">F</span><span class="special">::</span><span class="identifier">p_begin</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">F</span><span class="special">::</span><span class="identifier">p_end</span><span class="special">))</span><span class="special">
.</span><span class="identifier">property</span><span class="special">(</span><span class="string">"bogons"</span><span class="special">,</span><span class="identifier"> range</span><span class="special">(&amp;</span><span class="identifier">F</span><span class="special">::</span><span class="identifier">b_begin</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">F</span><span class="special">::</span><span class="identifier">b_end</span><span class="special">));</span></tt></pre>
<pre class="programlisting">
<span class="identifier">class_</span><span class="special">&lt;</span><span class="identifier">F</span><span class="special">&gt;(</span><span class="string">"Field"</span><span class="special">)</span>
<span class="special">.</span><span class="identifier">property</span><span class="special">(</span><span class="string">"pions"</span><span class="special">,</span> <span class="identifier">range</span><span class="special">(&amp;</span><span class="identifier">F</span><span class="special">::</span><span class="identifier">p_begin</span><span class="special">,</span> <span class="special">&amp;</span><span class="identifier">F</span><span class="special">::</span><span class="identifier">p_end</span><span class="special">))</span>
<span class="special">.</span><span class="identifier">property</span><span class="special">(</span><span class="string">"bogons"</span><span class="special">,</span> <span class="identifier">range</span><span class="special">(&amp;</span><span class="identifier">F</span><span class="special">::</span><span class="identifier">b_begin</span><span class="special">,</span> <span class="special">&amp;</span><span class="identifier">F</span><span class="special">::</span><span class="identifier">b_end</span><span class="special">));</span>
</pre>
<p><span class="bold"><b>stl_input_iterator</b></span></p>
<p>
So far, we have seen how to expose C++ iterators and ranges to Python. Sometimes
we wish to go the other way, though: we'd like to pass a Python sequence to
an STL algorithm or use it to initialize an STL container. We need to make
a Python iterator look like an STL iterator. For that, we use <tt class="computeroutput"><span class="identifier">stl_input_iterator</span><span class="special">&lt;&gt;</span></tt>.
Consider how we might implement a function that exposes <tt class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">list</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;::</span><span class="identifier">assign</span><span class="special">()</span></tt> to Python:
</p>
<p></p>
<pre class="programlisting">
<span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">&gt;</span>
<span class="keyword">void</span> <span class="identifier">list_assign</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">list</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;&amp;</span> <span class="identifier">l</span><span class="special">,</span> <span class="identifier">object</span> <span class="identifier">o</span><span class="special">)</span> <span class="special">{</span>
<span class="comment">// Turn a Python sequence into an STL input range
</span> <span class="identifier">stl_input_iterator</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;</span> <span class="identifier">begin</span><span class="special">(</span><span class="identifier">o</span><span class="special">),</span> <span class="identifier">end</span><span class="special">;</span>
<span class="identifier">l</span><span class="special">.</span><span class="identifier">assign</span><span class="special">(</span><span class="identifier">begin</span><span class="special">,</span> <span class="identifier">end</span><span class="special">);</span>
<span class="special">}</span>
<span class="comment">// Part of the wrapper for list&lt;int&gt;
</span><span class="identifier">class_</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">list</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;</span> <span class="special">&gt;(</span><span class="string">"list_int"</span><span class="special">)</span>
<span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"assign"</span><span class="special">,</span> <span class="special">&amp;</span><span class="identifier">list_assign</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;)</span>
<span class="comment">// ...
</span> <span class="special">;</span>
</pre>
<p>
Now in Python, we can assign any integer sequence to <tt class="computeroutput"><span class="identifier">list_int</span></tt>
objects:
</p>
<p></p>
<pre class="programlisting">
<span class="identifier">x</span> <span class="special">=</span> <span class="identifier">list_int</span><span class="special">();</span>
<span class="identifier">x</span><span class="special">.</span><span class="identifier">assign</span><span class="special">([</span><span class="number">1</span><span class="special">,</span><span class="number">2</span><span class="special">,</span><span class="number">3</span><span class="special">,</span><span class="number">4</span><span class="special">,</span><span class="number">5</span><span class="special">])</span>
</pre>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><small>Copyright © 2002-2005 Joel de Guzman, David Abrahams</small></td>
<td align="right"><small>Copyright © 2002-2005 Joel
de Guzman, David Abrahams</small></td>
</tr></table>
<hr>
<div class="spirit-nav">

View File

@ -32,234 +32,304 @@
<dt><span class="section"><a href="object.html#python.enums">Enums</a></span></dt>
</dl></div>
<p>
Python is dynamically typed, unlike C++ which is statically typed. Python
variables may hold an integer, a float, list, dict, tuple, str, long etc.,
among other things. In the viewpoint of Boost.Python and C++, these
Pythonic variables are just instances of class <tt class="literal">object</tt>. We shall see in
this chapter how to deal with Python objects.</p>
Object InterfacePython is dynamically typed, unlike C++ which is statically
typed. Python variables may hold an integer, a float, list, dict, tuple, str,
long etc., among other things. In the viewpoint of Boost.Python and C++, these
Pythonic variables are just instances of class <tt class="literal">object</tt>. We
shall see in this chapter how to deal with Python objects.
</p>
<p>
As mentioned, one of the goals of Boost.Python is to provide a
bidirectional mapping between C++ and Python while maintaining the Python
feel. Boost.Python C++ <tt class="literal">object</tt>s are as close as possible to Python. This
should minimize the learning curve significantly.</p>
As mentioned, one of the goals of Boost.Python is to provide a bidirectional
mapping between C++ and Python while maintaining the Python feel. Boost.Python
C++ <tt class="literal">object</tt>s are as close as possible to Python. This should
minimize the learning curve significantly.
</p>
<p><span class="inlinemediaobject"><img src="../images/python.png"></span></p>
<div class="section" lang="en">
<div class="titlepage"><div><div><h3 class="title">
<a name="python.basic_interface"></a>Basic Interface</h3></div></div></div>
<p>
Class <tt class="literal">object</tt> wraps <tt class="literal">PyObject*</tt>. All the intricacies of dealing with
<tt class="literal">PyObject</tt>s such as managing reference counting are handled by the
<tt class="literal">object</tt> class. C++ object interoperability is seamless. Boost.Python C++
<tt class="literal">object</tt>s can in fact be explicitly constructed from any C++ object.</p>
Basic InterfaceClass <tt class="literal">object</tt> wraps <tt class="literal">PyObject*</tt>.
All the intricacies of dealing with <tt class="literal">PyObject</tt>s such as
managing reference counting are handled by the <tt class="literal">object</tt>
class. C++ object interoperability is seamless. Boost.Python C++ <tt class="literal">object</tt>s
can in fact be explicitly constructed from any C++ object.
</p>
<p>
To illustrate, this Python code snippet:</p>
To illustrate, this Python code snippet:
</p>
<p></p>
<pre class="programlisting"><tt class="literal"><span class="keyword">def</span><span class="identifier"> f</span><span class="special">(</span><span class="identifier">x</span><span class="special">,</span><span class="identifier"> y</span><span class="special">):</span><span class="keyword">
if</span><span class="special"> (</span><span class="identifier">y</span><span class="special"> ==</span><span class="string"> 'foo'</span><span class="special">):</span><span class="identifier">
x</span><span class="special">[</span><span class="number">3</span><span class="special">:</span><span class="number">7</span><span class="special">]</span><span class="special"> =</span><span class="string"> 'bar'</span><span class="keyword">
else</span><span class="special">:</span><span class="identifier">
x</span><span class="special">.</span><span class="identifier">items</span><span class="special"> +=</span><span class="identifier"> y</span><span class="special">(</span><span class="number">3</span><span class="special">,</span><span class="identifier"> x</span><span class="special">)</span><span class="keyword">
return</span><span class="identifier"> x</span><span class="keyword">
<pre class="programlisting">
<span class="keyword">def</span> <span class="identifier">f</span><span class="special">(</span><span class="identifier">x</span><span class="special">,</span> <span class="identifier">y</span><span class="special">):</span>
<span class="keyword">if</span> <span class="special">(</span><span class="identifier">y</span> <span class="special">==</span> <span class="string">'foo'</span><span class="special">):</span>
<span class="identifier">x</span><span class="special">[</span><span class="number">3</span><span class="special">:</span><span class="number">7</span><span class="special">]</span> <span class="special">=</span> <span class="string">'bar'</span>
<span class="keyword">else</span><span class="special">:</span>
<span class="identifier">x</span><span class="special">.</span><span class="identifier">items</span> <span class="special">+=</span> <span class="identifier">y</span><span class="special">(</span><span class="number">3</span><span class="special">,</span> <span class="identifier">x</span><span class="special">)</span>
<span class="keyword">return</span> <span class="identifier">x</span>
def</span><span class="identifier"> getfunc</span><span class="special">():</span><span class="keyword">
return</span><span class="identifier"> f</span><span class="special">;</span></tt></pre>
<span class="keyword">def</span> <span class="identifier">getfunc</span><span class="special">():</span>
<span class="keyword">return</span> <span class="identifier">f</span><span class="special">;</span>
</pre>
<p>
Can be rewritten in C++ using Boost.Python facilities this way:</p>
Can be rewritten in C++ using Boost.Python facilities this way:
</p>
<p></p>
<pre class="programlisting"><tt class="literal"><span class="identifier">object</span><span class="identifier"> f</span><span class="special">(</span><span class="identifier">object</span><span class="identifier"> x</span><span class="special">,</span><span class="identifier"> object</span><span class="identifier"> y</span><span class="special">)</span><span class="special"> {</span><span class="keyword">
if</span><span class="special"> (</span><span class="identifier">y</span><span class="special"> ==</span><span class="string"> "foo"</span><span class="special">)</span><span class="identifier">
x</span><span class="special">.</span><span class="identifier">slice</span><span class="special">(</span><span class="number">3</span><span class="special">,</span><span class="number">7</span><span class="special">)</span><span class="special"> =</span><span class="string"> "bar"</span><span class="special">;</span><span class="keyword">
else</span><span class="identifier">
x</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"items"</span><span class="special">)</span><span class="special"> +=</span><span class="identifier"> y</span><span class="special">(</span><span class="number">3</span><span class="special">,</span><span class="identifier"> x</span><span class="special">);</span><span class="keyword">
return</span><span class="identifier"> x</span><span class="special">;</span><span class="special">
}</span><span class="identifier">
object</span><span class="identifier"> getfunc</span><span class="special">()</span><span class="special"> {</span><span class="keyword">
return</span><span class="identifier"> object</span><span class="special">(</span><span class="identifier">f</span><span class="special">);</span><span class="special">
}</span></tt></pre>
<pre class="programlisting">
<span class="identifier">object</span> <span class="identifier">f</span><span class="special">(</span><span class="identifier">object</span> <span class="identifier">x</span><span class="special">,</span> <span class="identifier">object</span> <span class="identifier">y</span><span class="special">)</span> <span class="special">{</span>
<span class="keyword">if</span> <span class="special">(</span><span class="identifier">y</span> <span class="special">==</span> <span class="string">"foo"</span><span class="special">)</span>
<span class="identifier">x</span><span class="special">.</span><span class="identifier">slice</span><span class="special">(</span><span class="number">3</span><span class="special">,</span><span class="number">7</span><span class="special">)</span> <span class="special">=</span> <span class="string">"bar"</span><span class="special">;</span>
<span class="keyword">else</span>
<span class="identifier">x</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"items"</span><span class="special">)</span> <span class="special">+=</span> <span class="identifier">y</span><span class="special">(</span><span class="number">3</span><span class="special">,</span> <span class="identifier">x</span><span class="special">);</span>
<span class="keyword">return</span> <span class="identifier">x</span><span class="special">;</span>
<span class="special">}</span>
<span class="identifier">object</span> <span class="identifier">getfunc</span><span class="special">()</span> <span class="special">{</span>
<span class="keyword">return</span> <span class="identifier">object</span><span class="special">(</span><span class="identifier">f</span><span class="special">);</span>
<span class="special">}</span>
</pre>
<p>
Apart from cosmetic differences due to the fact that we are writing the
code in C++, the look and feel should be immediately apparent to the Python
coder.</p>
Apart from cosmetic differences due to the fact that we are writing the code
in C++, the look and feel should be immediately apparent to the Python coder.
</p>
</div>
<div class="section" lang="en">
<div class="titlepage"><div><div><h3 class="title">
<a name="python.derived_object_types"></a>Derived Object types</h3></div></div></div>
<p>
Boost.Python comes with a set of derived <tt class="literal">object</tt> types corresponding to
that of Python's:</p>
Derived Object typesBoost.Python comes with a set of derived <tt class="literal">object</tt>
types corresponding to that of Python's:
</p>
<div class="itemizedlist"><ul type="disc">
<li>
list
</li>
list
</li>
<li>
dict
</li>
dict
</li>
<li>
tuple
</li>
tuple
</li>
<li>
str
</li>
str
</li>
<li>
long_
</li>
long_
</li>
<li>
enum
</li>
enum
</li>
</ul></div>
<p>
These derived <tt class="literal">object</tt> types act like real Python types. For instance:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">str</span><span class="special">(</span><span class="number">1</span><span class="special">)</span><span class="special"> ==&gt;</span><span class="string"> "1"</span></tt></pre>
These derived <tt class="literal">object</tt> types act like real Python types.
For instance:
</p>
<pre class="programlisting">
<span class="identifier">str</span><span class="special">(</span><span class="number">1</span><span class="special">)</span> <span class="special">==&gt;</span> <span class="string">"1"</span>
</pre>
<p>
Wherever appropriate, a particular derived <tt class="literal">object</tt> has corresponding
Python type's methods. For instance, <tt class="literal">dict</tt> has a <tt class="literal">keys()</tt> method:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">d</span><span class="special">.</span><span class="identifier">keys</span><span class="special">()</span></tt></pre>
<p><tt class="literal">make_tuple</tt> is provided for declaring <span class="emphasis"><em>tuple literals</em></span>. Example:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">make_tuple</span><span class="special">(</span><span class="number">123</span><span class="special">,</span><span class="char"> 'D'</span><span class="special">,</span><span class="string"> "Hello, World"</span><span class="special">,</span><span class="number"> 0.0</span><span class="special">);</span></tt></pre>
Wherever appropriate, a particular derived <tt class="literal">object</tt> has
corresponding Python type's methods. For instance, <tt class="literal">dict</tt>
has a <tt class="literal">keys()</tt> method:
</p>
<pre class="programlisting">
<span class="identifier">d</span><span class="special">.</span><span class="identifier">keys</span><span class="special">()</span>
</pre>
<p><tt class="literal">make_tuple</tt> is provided for declaring <span class="emphasis"><em>tuple literals</em></span>.
Example:
</p>
<pre class="programlisting">
<span class="identifier">make_tuple</span><span class="special">(</span><span class="number">123</span><span class="special">,</span> <span class="char">'D'</span><span class="special">,</span> <span class="string">"Hello, World"</span><span class="special">,</span> <span class="number">0.0</span><span class="special">);</span>
</pre>
<p>
In C++, when Boost.Python <tt class="literal">object</tt>s are used as arguments to functions,
subtype matching is required. For example, when a function <tt class="literal">f</tt>, as
declared below, is wrapped, it will only accept instances of Python's
<tt class="literal">str</tt> type and subtypes.</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">void</span><span class="identifier"> f</span><span class="special">(</span><span class="identifier">str</span><span class="identifier"> name</span><span class="special">)</span><span class="special">
{</span><span class="identifier">
object</span><span class="identifier"> n2</span><span class="special"> =</span><span class="identifier"> name</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"upper"</span><span class="special">)();</span><span class="comment"> // NAME = name.upper()
</span><span class="identifier"> str</span><span class="identifier"> NAME</span><span class="special"> =</span><span class="identifier"> name</span><span class="special">.</span><span class="identifier">upper</span><span class="special">();</span><span class="comment"> // better
</span><span class="identifier"> object</span><span class="identifier"> msg</span><span class="special"> =</span><span class="string"> "%s is bigger than %s"</span><span class="special"> %</span><span class="identifier"> make_tuple</span><span class="special">(</span><span class="identifier">NAME</span><span class="special">,</span><span class="identifier">name</span><span class="special">);</span><span class="special">
}</span></tt></pre>
In C++, when Boost.Python <tt class="literal">object</tt>s are used as arguments
to functions, subtype matching is required. For example, when a function
<tt class="literal">f</tt>, as declared below, is wrapped, it will only accept
instances of Python's <tt class="literal">str</tt> type and subtypes.
</p>
<pre class="programlisting">
<span class="keyword">void</span> <span class="identifier">f</span><span class="special">(</span><span class="identifier">str</span> <span class="identifier">name</span><span class="special">)</span>
<span class="special">{</span>
<span class="identifier">object</span> <span class="identifier">n2</span> <span class="special">=</span> <span class="identifier">name</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"upper"</span><span class="special">)();</span> <span class="comment">// NAME = name.upper()
</span> <span class="identifier">str</span> <span class="identifier">NAME</span> <span class="special">=</span> <span class="identifier">name</span><span class="special">.</span><span class="identifier">upper</span><span class="special">();</span> <span class="comment">// better
</span> <span class="identifier">object</span> <span class="identifier">msg</span> <span class="special">=</span> <span class="string">"%s is bigger than %s"</span> <span class="special">%</span> <span class="identifier">make_tuple</span><span class="special">(</span><span class="identifier">NAME</span><span class="special">,</span><span class="identifier">name</span><span class="special">);</span>
<span class="special">}</span>
</pre>
<p>
In finer detail:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">str</span><span class="identifier"> NAME</span><span class="special"> =</span><span class="identifier"> name</span><span class="special">.</span><span class="identifier">upper</span><span class="special">();</span></tt></pre>
In finer detail:
</p>
<pre class="programlisting">
<span class="identifier">str</span> <span class="identifier">NAME</span> <span class="special">=</span> <span class="identifier">name</span><span class="special">.</span><span class="identifier">upper</span><span class="special">();</span>
</pre>
<p>
Illustrates that we provide versions of the str type's methods as C++
member functions.</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">object</span><span class="identifier"> msg</span><span class="special"> =</span><span class="string"> "%s is bigger than %s"</span><span class="special"> %</span><span class="identifier"> make_tuple</span><span class="special">(</span><span class="identifier">NAME</span><span class="special">,</span><span class="identifier">name</span><span class="special">);</span></tt></pre>
Illustrates that we provide versions of the str type's methods as C++ member
functions.
</p>
<pre class="programlisting">
<span class="identifier">object</span> <span class="identifier">msg</span> <span class="special">=</span> <span class="string">"%s is bigger than %s"</span> <span class="special">%</span> <span class="identifier">make_tuple</span><span class="special">(</span><span class="identifier">NAME</span><span class="special">,</span><span class="identifier">name</span><span class="special">);</span>
</pre>
<p>
Demonstrates that you can write the C++ equivalent of <tt class="literal">"format" % x,y,z</tt>
in Python, which is useful since there's no easy way to do that in std C++.</p>
Demonstrates that you can write the C++ equivalent of <tt class="literal">"format"
% x,y,z</tt> in Python, which is useful since there's no easy way to
do that in std C++.
</p>
<div class="informaltable"><table class="table">
<colgroup><col></colgroup>
<tbody><tr><td class="blurb">
<span class="inlinemediaobject"><img src="../images/alert.png"></span><span class="bold"><b>Beware</b></span> the common pitfall of forgetting that the constructors
of most of Python's mutable types make copies, just as in Python.
</td></tr></tbody>
<span class="inlinemediaobject"><img src="../images/alert.png"></span> <span class="bold"><b>Beware</b></span> the common pitfall of forgetting that
the constructors of most of Python's mutable types make copies, just
as in Python. </td></tr></tbody>
</table></div>
<p>
Python:
</p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="identifier"> d</span><span class="special"> =</span><span class="identifier"> dict</span><span class="special">(</span><span class="identifier">x</span><span class="special">.</span><span class="identifier">__dict__</span><span class="special">)</span><span class="comment"> # copies x.__dict__
</span><span class="special">&gt;&gt;&gt;</span><span class="identifier"> d</span><span class="special">[</span><span class="string">'whatever'</span><span class="special">]</span><span class="comment"> # modifies the copy
</span></tt></pre>
Python:
</p>
<pre class="programlisting">
<span class="special">&gt;&gt;&gt;</span> <span class="identifier">d</span> <span class="special">=</span> <span class="identifier">dict</span><span class="special">(</span><span class="identifier">x</span><span class="special">.</span><span class="identifier">__dict__</span><span class="special">)</span> <span class="comment"># copies x.__dict__
</span><span class="special">&gt;&gt;&gt;</span> <span class="identifier">d</span><span class="special">[</span><span class="string">'whatever'</span><span class="special">]</span> <span class="special">=</span> <span class="number">3</span> <span class="comment"># modifies the copy
</span></pre>
<p>
C++:
</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">dict</span><span class="identifier"> d</span><span class="special">(</span><span class="identifier">x</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"__dict__"</span><span class="special">));</span><span class="comment"> // copies x.__dict__
</span><span class="identifier">d</span><span class="special">[</span><span class="char">'whatever'</span><span class="special">]</span><span class="special"> =</span><span class="number"> 3</span><span class="special">;</span><span class="comment"> // modifies the copy
</span></tt></pre>
C++:
</p>
<pre class="programlisting">
<span class="identifier">dict</span> <span class="identifier">d</span><span class="special">(</span><span class="identifier">x</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"__dict__"</span><span class="special">));</span> <span class="comment">// copies x.__dict__
</span><span class="identifier">d</span><span class="special">[</span><span class="char">'whatever'</span><span class="special">]</span> <span class="special">=</span> <span class="number">3</span><span class="special">;</span> <span class="comment">// modifies the copy
</span></pre>
<a name="derived_object_types.class__lt_t_gt__as_objects"></a><h2>
<a name="id454735"></a>class_&lt;T&gt; as objects</h2>
<a name="id455806"></a>
class_&lt;T&gt; as objects
</h2>
<p>
Due to the dynamic nature of Boost.Python objects, any <tt class="literal">class_&lt;T&gt;</tt> may
also be one of these types! The following code snippet wraps the class
(type) object.</p>
Due to the dynamic nature of Boost.Python objects, any <tt class="literal">class_&lt;T&gt;</tt>
may also be one of these types! The following code snippet wraps the class
(type) object.
</p>
<p>
We can use this to create wrapped instances. Example:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">object</span><span class="identifier"> vec345</span><span class="special"> =</span><span class="special"> (</span><span class="identifier">
class_</span><span class="special">&lt;</span><span class="identifier">Vec2</span><span class="special">&gt;(</span><span class="string">"Vec2"</span><span class="special">,</span><span class="identifier"> init</span><span class="special">&lt;</span><span class="keyword">double</span><span class="special">,</span><span class="keyword"> double</span><span class="special">&gt;())</span><span class="special">
.</span><span class="identifier">def_readonly</span><span class="special">(</span><span class="string">"length"</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">Point</span><span class="special">::</span><span class="identifier">length</span><span class="special">)</span><span class="special">
.</span><span class="identifier">def_readonly</span><span class="special">(</span><span class="string">"angle"</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">Point</span><span class="special">::</span><span class="identifier">angle</span><span class="special">)</span><span class="special">
)(</span><span class="number">3.0</span><span class="special">,</span><span class="number"> 4.0</span><span class="special">);</span><span class="identifier">
We can use this to create wrapped instances. Example:
</p>
<pre class="programlisting">
<span class="identifier">object</span> <span class="identifier">vec345</span> <span class="special">=</span> <span class="special">(</span>
<span class="identifier">class_</span><span class="special">&lt;</span><span class="identifier">Vec2</span><span class="special">&gt;(</span><span class="string">"Vec2"</span><span class="special">,</span> <span class="identifier">init</span><span class="special">&lt;</span><span class="keyword">double</span><span class="special">,</span> <span class="keyword">double</span><span class="special">&gt;())</span>
<span class="special">.</span><span class="identifier">def_readonly</span><span class="special">(</span><span class="string">"length"</span><span class="special">,</span> <span class="special">&amp;</span><span class="identifier">Point</span><span class="special">::</span><span class="identifier">length</span><span class="special">)</span>
<span class="special">.</span><span class="identifier">def_readonly</span><span class="special">(</span><span class="string">"angle"</span><span class="special">,</span> <span class="special">&amp;</span><span class="identifier">Point</span><span class="special">::</span><span class="identifier">angle</span><span class="special">)</span>
<span class="special">)(</span><span class="number">3.0</span><span class="special">,</span> <span class="number">4.0</span><span class="special">);</span>
assert</span><span class="special">(</span><span class="identifier">vec345</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"length"</span><span class="special">)</span><span class="special"> ==</span><span class="number"> 5.0</span><span class="special">);</span></tt></pre>
<span class="identifier">assert</span><span class="special">(</span><span class="identifier">vec345</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"length"</span><span class="special">)</span> <span class="special">==</span> <span class="number">5.0</span><span class="special">);</span>
</pre>
</div>
<div class="section" lang="en">
<div class="titlepage"><div><div><h3 class="title">
<a name="python.extracting_c___objects"></a>Extracting C++ objects</h3></div></div></div>
<p>
At some point, we will need to get C++ values out of object instances. This
can be achieved with the <tt class="literal">extract&lt;T&gt;</tt> function. Consider the following:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">double</span><span class="identifier"> x</span><span class="special"> =</span><span class="identifier"> o</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"length"</span><span class="special">);</span><span class="comment"> // compile error
</span></tt></pre>
Extracting C++ objectsAt some point, we will need to get C++ values out of
object instances. This can be achieved with the <tt class="literal">extract&lt;T&gt;</tt>
function. Consider the following:
</p>
<pre class="programlisting">
<span class="keyword">double</span> <span class="identifier">x</span> <span class="special">=</span> <span class="identifier">o</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"length"</span><span class="special">);</span> <span class="comment">// compile error
</span></pre>
<p>
In the code above, we got a compiler error because Boost.Python
<tt class="literal">object</tt> can't be implicitly converted to <tt class="literal">double</tt>s. Instead, what
we wanted to do above can be achieved by writing:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">double</span><span class="identifier"> l</span><span class="special"> =</span><span class="identifier"> extract</span><span class="special">&lt;</span><span class="keyword">double</span><span class="special">&gt;(</span><span class="identifier">o</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"length"</span><span class="special">));</span><span class="identifier">
Vec2</span><span class="special">&amp;</span><span class="identifier"> v</span><span class="special"> =</span><span class="identifier"> extract</span><span class="special">&lt;</span><span class="identifier">Vec2</span><span class="special">&amp;&gt;(</span><span class="identifier">o</span><span class="special">);</span><span class="identifier">
assert</span><span class="special">(</span><span class="identifier">l</span><span class="special"> ==</span><span class="identifier"> v</span><span class="special">.</span><span class="identifier">length</span><span class="special">());</span></tt></pre>
In the code above, we got a compiler error because Boost.Python <tt class="literal">object</tt>
can't be implicitly converted to <tt class="literal">double</tt>s. Instead, what
we wanted to do above can be achieved by writing:
</p>
<pre class="programlisting">
<span class="keyword">double</span> <span class="identifier">l</span> <span class="special">=</span> <span class="identifier">extract</span><span class="special">&lt;</span><span class="keyword">double</span><span class="special">&gt;(</span><span class="identifier">o</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"length"</span><span class="special">));</span>
<span class="identifier">Vec2</span><span class="special">&amp;</span> <span class="identifier">v</span> <span class="special">=</span> <span class="identifier">extract</span><span class="special">&lt;</span><span class="identifier">Vec2</span><span class="special">&amp;&gt;(</span><span class="identifier">o</span><span class="special">);</span>
<span class="identifier">assert</span><span class="special">(</span><span class="identifier">l</span> <span class="special">==</span> <span class="identifier">v</span><span class="special">.</span><span class="identifier">length</span><span class="special">());</span>
</pre>
<p>
The first line attempts to extract the "length" attribute of the Boost.Python
<tt class="literal">object</tt>. The second line attempts to <span class="emphasis"><em>extract</em></span> the <tt class="literal">Vec2</tt> object from held
by the Boost.Python <tt class="literal">object</tt>.</p>
The first line attempts to extract the "length" attribute of the
Boost.Python <tt class="literal">object</tt>. The second line attempts to <span class="emphasis"><em>extract</em></span>
the <tt class="literal">Vec2</tt> object from held by the Boost.Python <tt class="literal">object</tt>.
</p>
<p>
Take note that we said "attempt to" above. What if the Boost.Python <tt class="literal">object</tt>
does not really hold a <tt class="literal">Vec2</tt> type? This is certainly a possibility considering
the dynamic nature of Python <tt class="literal">object</tt>s. To be on the safe side, if the C++ type
can't be extracted, an appropriate exception is thrown. To avoid an exception,
we need to test for extractibility:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">extract</span><span class="special">&lt;</span><span class="identifier">Vec2</span><span class="special">&amp;&gt;</span><span class="identifier"> x</span><span class="special">(</span><span class="identifier">o</span><span class="special">);</span><span class="keyword">
if</span><span class="special"> (</span><span class="identifier">x</span><span class="special">.</span><span class="identifier">check</span><span class="special">())</span><span class="special"> {</span><span class="identifier">
Vec2</span><span class="special">&amp;</span><span class="identifier"> v</span><span class="special"> =</span><span class="identifier"> x</span><span class="special">();</span><span class="special"> ...</span></tt></pre>
<p><span class="inlinemediaobject"><img src="../images/tip.png"></span> The astute reader might have noticed that the <tt class="literal">extract&lt;T&gt;</tt>
facility in fact solves the mutable copying problem:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">dict</span><span class="identifier"> d</span><span class="special"> =</span><span class="identifier"> extract</span><span class="special">&lt;</span><span class="identifier">dict</span><span class="special">&gt;(</span><span class="identifier">x</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"__dict__"</span><span class="special">));</span><span class="identifier">
d</span><span class="special">[</span><span class="char">'whatever'</span><span class="special">]</span><span class="special"> =</span><span class="number"> 3</span><span class="special">;</span>          #<span class="identifier"> modifies</span><span class="identifier"> x</span><span class="special">.</span><span class="identifier">__dict__</span><span class="special"> !</span></tt></pre>
Take note that we said "attempt to" above. What if the Boost.Python
<tt class="literal">object</tt> does not really hold a <tt class="literal">Vec2</tt>
type? This is certainly a possibility considering the dynamic nature of Python
<tt class="literal">object</tt>s. To be on the safe side, if the C++ type can't
be extracted, an appropriate exception is thrown. To avoid an exception,
we need to test for extractibility:
</p>
<pre class="programlisting">
<span class="identifier">extract</span><span class="special">&lt;</span><span class="identifier">Vec2</span><span class="special">&amp;&gt;</span> <span class="identifier">x</span><span class="special">(</span><span class="identifier">o</span><span class="special">);</span>
<span class="keyword">if</span> <span class="special">(</span><span class="identifier">x</span><span class="special">.</span><span class="identifier">check</span><span class="special">())</span> <span class="special">{</span>
<span class="identifier">Vec2</span><span class="special">&amp;</span> <span class="identifier">v</span> <span class="special">=</span> <span class="identifier">x</span><span class="special">();</span> <span class="special">...</span>
</pre>
<p><span class="inlinemediaobject"><img src="../images/tip.png"></span>
The astute reader might have noticed that the <tt class="literal">extract&lt;T&gt;</tt>
facility in fact solves the mutable copying problem:
</p>
<pre class="programlisting">
<span class="identifier">dict</span> <span class="identifier">d</span> <span class="special">=</span> <span class="identifier">extract</span><span class="special">&lt;</span><span class="identifier">dict</span><span class="special">&gt;(</span><span class="identifier">x</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"__dict__"</span><span class="special">));</span>
<span class="identifier">d</span><span class="special">[</span><span class="string">"whatever"</span><span class="special">]</span> <span class="special">=</span> <span class="number">3</span><span class="special">;</span> <span class="comment">// modifies x.__dict__ !
</span></pre>
</div>
<div class="section" lang="en">
<div class="titlepage"><div><div><h3 class="title">
<a name="python.enums"></a>Enums</h3></div></div></div>
<p>
Boost.Python has a nifty facility to capture and wrap C++ enums. While
Python has no <tt class="literal">enum</tt> type, we'll often want to expose our C++ enums to
Python as an <tt class="literal">int</tt>. Boost.Python's enum facility makes this easy while
taking care of the proper conversions from Python's dynamic typing to C++'s
strong static typing (in C++, ints cannot be implicitly converted to
enums). To illustrate, given a C++ enum:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">enum</span><span class="identifier"> choice</span><span class="special"> {</span><span class="identifier"> red</span><span class="special">,</span><span class="identifier"> blue</span><span class="special"> };</span></tt></pre>
EnumsBoost.Python has a nifty facility to capture and wrap C++ enums. While
Python has no <tt class="literal">enum</tt> type, we'll often want to expose our
C++ enums to Python as an <tt class="literal">int</tt>. Boost.Python's enum facility
makes this easy while taking care of the proper conversions from Python's
dynamic typing to C++'s strong static typing (in C++, ints cannot be implicitly
converted to enums). To illustrate, given a C++ enum:
</p>
<pre class="programlisting">
<span class="keyword">enum</span> <span class="identifier">choice</span> <span class="special">{</span> <span class="identifier">red</span><span class="special">,</span> <span class="identifier">blue</span> <span class="special">};</span>
</pre>
<p>
the construct:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">enum_</span><span class="special">&lt;</span><span class="identifier">choice</span><span class="special">&gt;(</span><span class="string">"choice"</span><span class="special">)</span><span class="special">
.</span><span class="identifier">value</span><span class="special">(</span><span class="string">"red"</span><span class="special">,</span><span class="identifier"> red</span><span class="special">)</span><span class="special">
.</span><span class="identifier">value</span><span class="special">(</span><span class="string">"blue"</span><span class="special">,</span><span class="identifier"> blue</span><span class="special">)</span><span class="special">
;</span></tt></pre>
the construct:
</p>
<pre class="programlisting">
<span class="identifier">enum_</span><span class="special">&lt;</span><span class="identifier">choice</span><span class="special">&gt;(</span><span class="string">"choice"</span><span class="special">)</span>
<span class="special">.</span><span class="identifier">value</span><span class="special">(</span><span class="string">"red"</span><span class="special">,</span> <span class="identifier">red</span><span class="special">)</span>
<span class="special">.</span><span class="identifier">value</span><span class="special">(</span><span class="string">"blue"</span><span class="special">,</span> <span class="identifier">blue</span><span class="special">)</span>
<span class="special">;</span>
</pre>
<p>
can be used to expose to Python. The new enum type is created in the
current <tt class="literal">scope()</tt>, which is usually the current module. The snippet above
creates a Python class derived from Python's <tt class="literal">int</tt> type which is
associated with the C++ type passed as its first parameter.</p>
can be used to expose to Python. The new enum type is created in the current
<tt class="literal">scope()</tt>, which is usually the current module. The snippet
above creates a Python class derived from Python's <tt class="literal">int</tt>
type which is associated with the C++ type passed as its first parameter.
</p>
<div class="informaltable"><table class="table">
<colgroup><col></colgroup>
<tbody><tr><td class="blurb">
<span class="inlinemediaobject"><img src="../images/note.png"></span><span class="bold"><b>what is a scope?</b></span><br><br>
The scope is a class that has an
associated global Python object which controls the Python namespace in
which new extension classes and wrapped functions will be defined as
attributes. Details can be found <a href="../../../../v2/scope.html" target="_top">here</a>.</td></tr></tbody>
<span class="inlinemediaobject"><img src="../images/note.png"></span> <span class="bold"><b>what is a scope?</b></span><br><br> The scope is a
class that has an associated global Python object which controls the
Python namespace in which new extension classes and wrapped functions
will be defined as attributes. Details can be found <a href="../../../../v2/scope.html" target="_top">here</a>.</td></tr></tbody>
</table></div>
<p>
You can access those values in Python as</p>
You can access those values in Python as
</p>
<p></p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="identifier"> my_module</span><span class="special">.</span><span class="identifier">choice</span><span class="special">.</span><span class="identifier">red</span><span class="identifier">
my_module</span><span class="special">.</span><span class="identifier">choice</span><span class="special">.</span><span class="identifier">red</span></tt></pre>
<pre class="programlisting">
<span class="special">&gt;&gt;&gt;</span> <span class="identifier">my_module</span><span class="special">.</span><span class="identifier">choice</span><span class="special">.</span><span class="identifier">red</span>
<span class="identifier">my_module</span><span class="special">.</span><span class="identifier">choice</span><span class="special">.</span><span class="identifier">red</span>
</pre>
<p>
where my_module is the module where the enum is declared. You can also
create a new scope around a class:</p>
where my_module is the module where the enum is declared. You can also create
a new scope around a class:
</p>
<p></p>
<pre class="programlisting"><tt class="literal"><span class="identifier">scope</span><span class="identifier"> in_X</span><span class="special"> =</span><span class="identifier"> class_</span><span class="special">&lt;</span><span class="identifier">X</span><span class="special">&gt;(</span><span class="string">"X"</span><span class="special">)</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="special"> ...</span><span class="special"> )</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="special"> ...</span><span class="special"> )</span><span class="special">
;</span><span class="comment">
<pre class="programlisting">
<span class="identifier">scope</span> <span class="identifier">in_X</span> <span class="special">=</span> <span class="identifier">class_</span><span class="special">&lt;</span><span class="identifier">X</span><span class="special">&gt;(</span><span class="string">"X"</span><span class="special">)</span>
<span class="special">.</span><span class="identifier">def</span><span class="special">(</span> <span class="special">...</span> <span class="special">)</span>
<span class="special">.</span><span class="identifier">def</span><span class="special">(</span> <span class="special">...</span> <span class="special">)</span>
<span class="special">;</span>
// Expose X::nested as X.nested
</span><span class="identifier">enum_</span><span class="special">&lt;</span><span class="identifier">X</span><span class="special">::</span><span class="identifier">nested</span><span class="special">&gt;(</span><span class="string">"nested"</span><span class="special">)</span><span class="special">
.</span><span class="identifier">value</span><span class="special">(</span><span class="string">"red"</span><span class="special">,</span><span class="identifier"> red</span><span class="special">)</span><span class="special">
.</span><span class="identifier">value</span><span class="special">(</span><span class="string">"blue"</span><span class="special">,</span><span class="identifier"> blue</span><span class="special">)</span><span class="special">
;</span></tt></pre>
<span class="comment">// Expose X::nested as X.nested
</span><span class="identifier">enum_</span><span class="special">&lt;</span><span class="identifier">X</span><span class="special">::</span><span class="identifier">nested</span><span class="special">&gt;(</span><span class="string">"nested"</span><span class="special">)</span>
<span class="special">.</span><span class="identifier">value</span><span class="special">(</span><span class="string">"red"</span><span class="special">,</span> <span class="identifier">red</span><span class="special">)</span>
<span class="special">.</span><span class="identifier">value</span><span class="special">(</span><span class="string">"blue"</span><span class="special">,</span> <span class="identifier">blue</span><span class="special">)</span>
<span class="special">;</span>
</pre>
</div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><small>Copyright © 2002-2005 Joel de Guzman, David Abrahams</small></td>
<td align="right"><small>Copyright © 2002-2005 Joel
de Guzman, David Abrahams</small></td>
</tr></table>
<hr>
<div class="spirit-nav">

View File

@ -30,109 +30,138 @@
<dt><span class="section"><a href="techniques.html#python.reducing_compiling_time">Reducing Compiling Time</a></span></dt>
</dl></div>
<p>
Here are presented some useful techniques that you can use while wrapping code with Boost.Python.</p>
General TechniquesHere are presented some useful techniques that you can use
while wrapping code with Boost.Python.
</p>
<div class="section" lang="en">
<div class="titlepage"><div><div><h3 class="title">
<a name="python.creating_packages"></a>Creating Packages</h3></div></div></div>
<p>
A Python package is a collection of modules that provide to the user a certain
functionality. If you're not familiar on how to create packages, a good
introduction to them is provided in the
<a href="http://www.python.org/doc/current/tut/node8.html" target="_top">Python Tutorial</a>.</p>
Creating PackagesA Python package is a collection of modules that provide
to the user a certain functionality. If you're not familiar on how to create
packages, a good introduction to them is provided in the <a href="http://www.python.org/doc/current/tut/node8.html" target="_top">Python
Tutorial</a>.
</p>
<p>
But we are wrapping C++ code, using Boost.Python. How can we provide a nice
package interface to our users? To better explain some concepts, let's work
with an example.</p>
But we are wrapping C++ code, using Boost.Python. How can we provide a nice
package interface to our users? To better explain some concepts, let's work
with an example.
</p>
<p>
We have a C++ library that works with sounds: reading and writing various
formats, applying filters to the sound data, etc. It is named (conveniently)
<tt class="literal">sounds</tt>. Our library already has a neat C++ namespace hierarchy, like so:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">sounds</span><span class="special">::</span><span class="identifier">core</span><span class="identifier">
sounds</span><span class="special">::</span><span class="identifier">io</span><span class="identifier">
sounds</span><span class="special">::</span><span class="identifier">filters</span></tt></pre>
We have a C++ library that works with sounds: reading and writing various
formats, applying filters to the sound data, etc. It is named (conveniently)
<tt class="literal">sounds</tt>. Our library already has a neat C++ namespace hierarchy,
like so:
</p>
<pre class="programlisting">
<span class="identifier">sounds</span><span class="special">::</span><span class="identifier">core</span>
<span class="identifier">sounds</span><span class="special">::</span><span class="identifier">io</span>
<span class="identifier">sounds</span><span class="special">::</span><span class="identifier">filters</span>
</pre>
<p>
We would like to present this same hierarchy to the Python user, allowing him
to write code like this:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">import</span><span class="identifier"> sounds</span><span class="special">.</span><span class="identifier">filters</span><span class="identifier">
sounds</span><span class="special">.</span><span class="identifier">filters</span><span class="special">.</span><span class="identifier">echo</span><span class="special">(...)</span> #<span class="identifier"> echo</span><span class="identifier"> is</span><span class="identifier"> a</span><span class="identifier"> C</span><span class="special">++</span><span class="identifier"> function</span></tt></pre>
We would like to present this same hierarchy to the Python user, allowing
him to write code like this:
</p>
<pre class="programlisting">
<span class="keyword">import</span> <span class="identifier">sounds</span><span class="special">.</span><span class="identifier">filters</span>
<span class="identifier">sounds</span><span class="special">.</span><span class="identifier">filters</span><span class="special">.</span><span class="identifier">echo</span><span class="special">(...)</span> <span class="comment"># echo is a C++ function
</span></pre>
<p>
The first step is to write the wrapping code. We have to export each module
separately with Boost.Python, like this:</p>
<pre class="programlisting"><tt class="literal"><span class="comment">/* file core.cpp */</span><span class="identifier">
BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">core</span><span class="special">)</span><span class="special">
{</span><span class="comment">
/* export everything in the sounds::core namespace */</span><span class="special">
...</span><span class="special">
}</span><span class="comment">
The first step is to write the wrapping code. We have to export each module
separately with Boost.Python, like this:
</p>
<pre class="programlisting">
<span class="special">/*</span> <span class="identifier">file</span> <span class="identifier">core</span><span class="special">.</span><span class="identifier">cpp</span> <span class="special">*/</span>
<span class="identifier">BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">core</span><span class="special">)</span>
<span class="special">{</span>
<span class="special">/*</span> <span class="identifier">export</span> <span class="identifier">everything</span> <span class="keyword">in</span> <span class="identifier">the</span> <span class="identifier">sounds</span><span class="special">::</span><span class="identifier">core</span> <span class="identifier">namespace</span> <span class="special">*/</span>
<span class="special">...</span>
<span class="special">}</span>
/* file io.cpp */</span><span class="identifier">
BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">io</span><span class="special">)</span><span class="special">
{</span><span class="comment">
/* export everything in the sounds::io namespace */</span><span class="special">
...</span><span class="special">
}</span><span class="comment">
<span class="special">/*</span> <span class="identifier">file</span> <span class="identifier">io</span><span class="special">.</span><span class="identifier">cpp</span> <span class="special">*/</span>
<span class="identifier">BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">io</span><span class="special">)</span>
<span class="special">{</span>
<span class="special">/*</span> <span class="identifier">export</span> <span class="identifier">everything</span> <span class="keyword">in</span> <span class="identifier">the</span> <span class="identifier">sounds</span><span class="special">::</span><span class="identifier">io</span> <span class="identifier">namespace</span> <span class="special">*/</span>
<span class="special">...</span>
<span class="special">}</span>
/* file filters.cpp */</span><span class="identifier">
BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">filters</span><span class="special">)</span><span class="special">
{</span><span class="comment">
/* export everything in the sounds::filters namespace */</span><span class="special">
...</span><span class="special">
}</span></tt></pre>
<span class="special">/*</span> <span class="identifier">file</span> <span class="identifier">filters</span><span class="special">.</span><span class="identifier">cpp</span> <span class="special">*/</span>
<span class="identifier">BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">filters</span><span class="special">)</span>
<span class="special">{</span>
<span class="special">/*</span> <span class="identifier">export</span> <span class="identifier">everything</span> <span class="keyword">in</span> <span class="identifier">the</span> <span class="identifier">sounds</span><span class="special">::</span><span class="identifier">filters</span> <span class="identifier">namespace</span> <span class="special">*/</span>
<span class="special">...</span>
<span class="special">}</span>
</pre>
<p>
Compiling these files will generate the following Python extensions:
<tt class="literal">core.pyd</tt>, <tt class="literal">io.pyd</tt> and <tt class="literal">filters.pyd</tt>.</p>
Compiling these files will generate the following Python extensions: <tt class="literal">core.pyd</tt>,
<tt class="literal">io.pyd</tt> and <tt class="literal">filters.pyd</tt>.
</p>
<div class="informaltable"><table class="table">
<colgroup><col></colgroup>
<tbody><tr><td class="blurb">
<span class="inlinemediaobject"><img src="../images/note.png"></span> The extension <tt class="literal">.pyd</tt> is used for python extension modules, which
are just shared libraries. Using the default for your system, like <tt class="literal">.so</tt> for
Unix and <tt class="literal">.dll</tt> for Windows, works just as well.</td></tr></tbody>
<span class="inlinemediaobject"><img src="../images/note.png"></span>
The extension <tt class="literal">.pyd</tt> is used for python extension
modules, which are just shared libraries. Using the default for your
system, like <tt class="literal">.so</tt> for Unix and <tt class="literal">.dll</tt>
for Windows, works just as well.</td></tr></tbody>
</table></div>
<p>
Now, we create this directory structure for our Python package:</p>
<pre class="programlisting"><tt class="literal">sounds/
Now, we create this directory structure for our Python package:
</p>
<pre class="programlisting">sounds/
__init__.py
core.pyd
filters.pyd
io.pyd
</tt></pre>
</pre>
<p>
The file <tt class="literal">__init__.py</tt> is what tells Python that the directory <tt class="literal">sounds/</tt> is
actually a Python package. It can be a empty file, but can also perform some
magic, that will be shown later.</p>
The file <tt class="literal">__init__.py</tt> is what tells Python that the directory
<tt class="literal">sounds/</tt> is actually a Python package. It can be a empty
file, but can also perform some magic, that will be shown later.
</p>
<p>
Now our package is ready. All the user has to do is put <tt class="literal">sounds</tt> into his
<a href="http://www.python.org/doc/current/tut/node8.html#SECTION008110000000000000000" target="_top">PYTHONPATH</a>
and fire up the interpreter:</p>
Now our package is ready. All the user has to do is put <tt class="literal">sounds</tt>
into his <a href="http://www.python.org/doc/current/tut/node8.html#SECTION008110000000000000000" target="_top">PYTHONPATH</a>
and fire up the interpreter:
</p>
<p></p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="keyword"> import</span><span class="identifier"> sounds</span><span class="special">.</span><span class="identifier">io</span><span class="special">
&gt;&gt;&gt;</span><span class="keyword"> import</span><span class="identifier"> sounds</span><span class="special">.</span><span class="identifier">filters</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> sound</span><span class="special"> =</span><span class="identifier"> sounds</span><span class="special">.</span><span class="identifier">io</span><span class="special">.</span><span class="identifier">open</span><span class="special">(</span><span class="string">'file.mp3'</span><span class="special">)</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> new_sound</span><span class="special"> =</span><span class="identifier"> sounds</span><span class="special">.</span><span class="identifier">filters</span><span class="special">.</span><span class="identifier">echo</span><span class="special">(</span><span class="identifier">sound</span><span class="special">,</span><span class="number"> 1.0</span><span class="special">)</span></tt></pre>
<pre class="programlisting">
<span class="special">&gt;&gt;&gt;</span> <span class="keyword">import</span> <span class="identifier">sounds</span><span class="special">.</span><span class="identifier">io</span>
<span class="special">&gt;&gt;&gt;</span> <span class="keyword">import</span> <span class="identifier">sounds</span><span class="special">.</span><span class="identifier">filters</span>
<span class="special">&gt;&gt;&gt;</span> <span class="identifier">sound</span> <span class="special">=</span> <span class="identifier">sounds</span><span class="special">.</span><span class="identifier">io</span><span class="special">.</span><span class="identifier">open</span><span class="special">(</span><span class="string">'file.mp3'</span><span class="special">)</span>
<span class="special">&gt;&gt;&gt;</span> <span class="identifier">new_sound</span> <span class="special">=</span> <span class="identifier">sounds</span><span class="special">.</span><span class="identifier">filters</span><span class="special">.</span><span class="identifier">echo</span><span class="special">(</span><span class="identifier">sound</span><span class="special">,</span> <span class="number">1.0</span><span class="special">)</span>
</pre>
<p>
Nice heh?</p>
Nice heh?
</p>
<p>
This is the simplest way to create hierarchies of packages, but it is not very
flexible. What if we want to add a <span class="emphasis"><em>pure</em></span> Python function to the filters
package, for instance, one that applies 3 filters in a sound object at once?
Sure, you can do this in C++ and export it, but why not do so in Python? You
don't have to recompile the extension modules, plus it will be easier to write
it.</p>
This is the simplest way to create hierarchies of packages, but it is not
very flexible. What if we want to add a <span class="emphasis"><em>pure</em></span> Python
function to the filters package, for instance, one that applies 3 filters
in a sound object at once? Sure, you can do this in C++ and export it, but
why not do so in Python? You don't have to recompile the extension modules,
plus it will be easier to write it.
</p>
<p>
If we want this flexibility, we will have to complicate our package hierarchy a
little. First, we will have to change the name of the extension modules:</p>
If we want this flexibility, we will have to complicate our package hierarchy
a little. First, we will have to change the name of the extension modules:
</p>
<p></p>
<pre class="programlisting"><tt class="literal"><span class="comment">/* file core.cpp */</span><span class="identifier">
BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">_core</span><span class="special">)</span><span class="special">
{</span><span class="special">
...</span><span class="comment">
/* export everything in the sounds::core namespace */</span><span class="special">
}</span></tt></pre>
<pre class="programlisting">
<span class="comment">/* file core.cpp */</span>
<span class="identifier">BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">_core</span><span class="special">)</span>
<span class="special">{</span>
<span class="special">...</span>
<span class="comment">/* export everything in the sounds::core namespace */</span>
<span class="special">}</span>
</pre>
<p>
Note that we added an underscore to the module name. The filename will have to
be changed to <tt class="literal">_core.pyd</tt> as well, and we do the same to the other extension modules.
Now, we change our package hierarchy like so:</p>
<pre class="programlisting"><tt class="literal">sounds/
Note that we added an underscore to the module name. The filename will have
to be changed to <tt class="literal">_core.pyd</tt> as well, and we do the same
to the other extension modules. Now, we change our package hierarchy like
so:
</p>
<pre class="programlisting">sounds/
__init__.py
core/
__init__.py
@ -143,220 +172,275 @@ Now, we change our package hierarchy like so:</p>
io/
__init__.py
_io.pyd
</tt></pre>
</pre>
<p>
Note that we created a directory for each extension module, and added a
__init__.py to each one. But if we leave it that way, the user will have to
access the functions in the core module with this syntax:</p>
Note that we created a directory for each extension module, and added a __init__.py
to each one. But if we leave it that way, the user will have to access the
functions in the core module with this syntax:
</p>
<p></p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="keyword"> import</span><span class="identifier"> sounds</span><span class="special">.</span><span class="identifier">core</span><span class="special">.</span><span class="identifier">_core</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> sounds</span><span class="special">.</span><span class="identifier">core</span><span class="special">.</span><span class="identifier">_core</span><span class="special">.</span><span class="identifier">foo</span><span class="special">(...)</span></tt></pre>
<pre class="programlisting">
<span class="special">&gt;&gt;&gt;</span> <span class="keyword">import</span> <span class="identifier">sounds</span><span class="special">.</span><span class="identifier">core</span><span class="special">.</span><span class="identifier">_core</span>
<span class="special">&gt;&gt;&gt;</span> <span class="identifier">sounds</span><span class="special">.</span><span class="identifier">core</span><span class="special">.</span><span class="identifier">_core</span><span class="special">.</span><span class="identifier">foo</span><span class="special">(...)</span>
</pre>
<p>
which is not what we want. But here enters the <tt class="literal">__init__.py</tt> magic: everything
that is brought to the <tt class="literal">__init__.py</tt> namespace can be accessed directly by the
user. So, all we have to do is bring the entire namespace from <tt class="literal">_core.pyd</tt>
to <tt class="literal">core/__init__.py</tt>. So add this line of code to <tt class="literal">sounds<span class="emphasis"><em>core</em></span>__init__.py</tt>:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">from</span><span class="identifier"> _core</span><span class="keyword"> import</span><span class="special"> *</span></tt></pre>
which is not what we want. But here enters the <tt class="literal">__init__.py</tt>
magic: everything that is brought to the <tt class="literal">__init__.py</tt> namespace
can be accessed directly by the user. So, all we have to do is bring the
entire namespace from <tt class="literal">_core.pyd</tt> to <tt class="literal">core/__init__.py</tt>.
So add this line of code to <tt class="literal">sounds<span class="emphasis"><em>core</em></span>__init__.py</tt>:
</p>
<pre class="programlisting">
<span class="keyword">from</span> <span class="identifier">_core</span> <span class="keyword">import</span> <span class="special">*</span>
</pre>
<p>
We do the same for the other packages. Now the user accesses the functions and
classes in the extension modules like before:</p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="keyword"> import</span><span class="identifier"> sounds</span><span class="special">.</span><span class="identifier">filters</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> sounds</span><span class="special">.</span><span class="identifier">filters</span><span class="special">.</span><span class="identifier">echo</span><span class="special">(...)</span></tt></pre>
We do the same for the other packages. Now the user accesses the functions
and classes in the extension modules like before:
</p>
<pre class="programlisting">
<span class="special">&gt;&gt;&gt;</span> <span class="keyword">import</span> <span class="identifier">sounds</span><span class="special">.</span><span class="identifier">filters</span>
<span class="special">&gt;&gt;&gt;</span> <span class="identifier">sounds</span><span class="special">.</span><span class="identifier">filters</span><span class="special">.</span><span class="identifier">echo</span><span class="special">(...)</span>
</pre>
<p>
with the additional benefit that we can easily add pure Python functions to
any module, in a way that the user can't tell the difference between a C++
function and a Python function. Let's add a <span class="emphasis"><em>pure</em></span> Python function,
<tt class="literal">echo_noise</tt>, to the <tt class="literal">filters</tt> package. This function applies both the
<tt class="literal">echo</tt> and <tt class="literal">noise</tt> filters in sequence in the given <tt class="literal">sound</tt> object. We
create a file named <tt class="literal">sounds/filters/echo_noise.py</tt> and code our function:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">import</span><span class="identifier"> _filters</span><span class="keyword">
def</span><span class="identifier"> echo_noise</span><span class="special">(</span><span class="identifier">sound</span><span class="special">):</span><span class="identifier">
s</span><span class="special"> =</span><span class="identifier"> _filters</span><span class="special">.</span><span class="identifier">echo</span><span class="special">(</span><span class="identifier">sound</span><span class="special">)</span><span class="identifier">
s</span><span class="special"> =</span><span class="identifier"> _filters</span><span class="special">.</span><span class="identifier">noise</span><span class="special">(</span><span class="identifier">sound</span><span class="special">)</span><span class="keyword">
return</span><span class="identifier"> s</span></tt></pre>
with the additional benefit that we can easily add pure Python functions
to any module, in a way that the user can't tell the difference between a
C++ function and a Python function. Let's add a <span class="emphasis"><em>pure</em></span>
Python function, <tt class="literal">echo_noise</tt>, to the <tt class="literal">filters</tt>
package. This function applies both the <tt class="literal">echo</tt> and <tt class="literal">noise</tt>
filters in sequence in the given <tt class="literal">sound</tt> object. We create
a file named <tt class="literal">sounds/filters/echo_noise.py</tt> and code our
function:
</p>
<pre class="programlisting">
<span class="keyword">import</span> <span class="identifier">_filters</span>
<span class="keyword">def</span> <span class="identifier">echo_noise</span><span class="special">(</span><span class="identifier">sound</span><span class="special">):</span>
<span class="identifier">s</span> <span class="special">=</span> <span class="identifier">_filters</span><span class="special">.</span><span class="identifier">echo</span><span class="special">(</span><span class="identifier">sound</span><span class="special">)</span>
<span class="identifier">s</span> <span class="special">=</span> <span class="identifier">_filters</span><span class="special">.</span><span class="identifier">noise</span><span class="special">(</span><span class="identifier">sound</span><span class="special">)</span>
<span class="keyword">return</span> <span class="identifier">s</span>
</pre>
<p>
Next, we add this line to <tt class="literal">sounds<span class="emphasis"><em>filters</em></span>__init__.py</tt>:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">from</span><span class="identifier"> echo_noise</span><span class="keyword"> import</span><span class="identifier"> echo_noise</span></tt></pre>
Next, we add this line to <tt class="literal">sounds<span class="emphasis"><em>filters</em></span>__init__.py</tt>:
</p>
<pre class="programlisting">
<span class="keyword">from</span> <span class="identifier">echo_noise</span> <span class="keyword">import</span> <span class="identifier">echo_noise</span>
</pre>
<p>
And that's it. The user now accesses this function like any other function
from the <tt class="literal">filters</tt> package:</p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="keyword"> import</span><span class="identifier"> sounds</span><span class="special">.</span><span class="identifier">filters</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> sounds</span><span class="special">.</span><span class="identifier">filters</span><span class="special">.</span><span class="identifier">echo_noise</span><span class="special">(...)</span></tt></pre>
And that's it. The user now accesses this function like any other function
from the <tt class="literal">filters</tt> package:
</p>
<pre class="programlisting">
<span class="special">&gt;&gt;&gt;</span> <span class="keyword">import</span> <span class="identifier">sounds</span><span class="special">.</span><span class="identifier">filters</span>
<span class="special">&gt;&gt;&gt;</span> <span class="identifier">sounds</span><span class="special">.</span><span class="identifier">filters</span><span class="special">.</span><span class="identifier">echo_noise</span><span class="special">(...)</span>
</pre>
</div>
<div class="section" lang="en">
<div class="titlepage"><div><div><h3 class="title">
<a name="python.extending_wrapped_objects_in_python"></a>Extending Wrapped Objects in Python</h3></div></div></div>
<p>
Thanks to Python's flexibility, you can easily add new methods to a class,
even after it was already created:</p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="keyword"> class</span><span class="identifier"> C</span><span class="special">(</span><span class="identifier">object</span><span class="special">):</span><span class="keyword"> pass</span><span class="special">
&gt;&gt;&gt;</span><span class="special">
&gt;&gt;&gt;</span><span class="comment"> # a regular function
</span><span class="special">&gt;&gt;&gt;</span><span class="keyword"> def</span><span class="identifier"> C_str</span><span class="special">(</span><span class="identifier">self</span><span class="special">):</span><span class="keyword"> return</span><span class="string"> 'A C instance!'</span><span class="special">
&gt;&gt;&gt;</span><span class="special">
&gt;&gt;&gt;</span><span class="comment"> # now we turn it in a member function
</span><span class="special">&gt;&gt;&gt;</span><span class="identifier"> C</span><span class="special">.</span><span class="identifier">__str__</span><span class="special"> =</span><span class="identifier"> C_str</span><span class="special">
&gt;&gt;&gt;</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> c</span><span class="special"> =</span><span class="identifier"> C</span><span class="special">()</span><span class="special">
&gt;&gt;&gt;</span><span class="keyword"> print</span><span class="identifier"> c</span><span class="identifier">
A</span><span class="identifier"> C</span><span class="identifier"> instance</span><span class="special">!</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> C_str</span><span class="special">(</span><span class="identifier">c</span><span class="special">)</span><span class="identifier">
A</span><span class="identifier"> C</span><span class="identifier"> instance</span><span class="special">!</span></tt></pre>
Extending Wrapped Objects in PythonThanks to Python's flexibility, you can
easily add new methods to a class, even after it was already created:
</p>
<pre class="programlisting">
<span class="special">&gt;&gt;&gt;</span> <span class="keyword">class</span> <span class="identifier">C</span><span class="special">(</span><span class="identifier">object</span><span class="special">):</span> <span class="keyword">pass</span>
<span class="special">&gt;&gt;&gt;</span>
<span class="special">&gt;&gt;&gt;</span> <span class="comment"># a regular function
</span><span class="special">&gt;&gt;&gt;</span> <span class="keyword">def</span> <span class="identifier">C_str</span><span class="special">(</span><span class="identifier">self</span><span class="special">):</span> <span class="keyword">return</span> <span class="string">'A C instance!'</span>
<span class="special">&gt;&gt;&gt;</span>
<span class="special">&gt;&gt;&gt;</span> <span class="comment"># now we turn it in a member function
</span><span class="special">&gt;&gt;&gt;</span> <span class="identifier">C</span><span class="special">.</span><span class="identifier">__str__</span> <span class="special">=</span> <span class="identifier">C_str</span>
<span class="special">&gt;&gt;&gt;</span>
<span class="special">&gt;&gt;&gt;</span> <span class="identifier">c</span> <span class="special">=</span> <span class="identifier">C</span><span class="special">()</span>
<span class="special">&gt;&gt;&gt;</span> <span class="keyword">print</span> <span class="identifier">c</span>
<span class="identifier">A</span> <span class="identifier">C</span> <span class="identifier">instance</span><span class="special">!</span>
<span class="special">&gt;&gt;&gt;</span> <span class="identifier">C_str</span><span class="special">(</span><span class="identifier">c</span><span class="special">)</span>
<span class="identifier">A</span> <span class="identifier">C</span> <span class="identifier">instance</span><span class="special">!</span>
</pre>
<p>
Yes, Python rox. <span class="inlinemediaobject"><img src="../images/smiley.png"></span></p>
Yes, Python rox. <span class="inlinemediaobject"><img src="../images/smiley.png"></span></p>
<p>
We can do the same with classes that were wrapped with Boost.Python. Suppose
we have a class <tt class="literal">point</tt> in C++:</p>
We can do the same with classes that were wrapped with Boost.Python. Suppose
we have a class <tt class="literal">point</tt> in C++:
</p>
<p></p>
<pre class="programlisting"><tt class="literal"><span class="keyword">class</span><span class="identifier"> point</span><span class="special"> {...};</span><span class="identifier">
<pre class="programlisting">
<span class="keyword">class</span> <span class="identifier">point</span> <span class="special">{...};</span>
BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">_geom</span><span class="special">)</span><span class="special">
{</span><span class="identifier">
class_</span><span class="special">&lt;</span><span class="identifier">point</span><span class="special">&gt;(</span><span class="string">"point"</span><span class="special">)...;</span><span class="special">
}</span></tt></pre>
<span class="identifier">BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">_geom</span><span class="special">)</span>
<span class="special">{</span>
<span class="identifier">class_</span><span class="special">&lt;</span><span class="identifier">point</span><span class="special">&gt;(</span><span class="string">"point"</span><span class="special">)...;</span>
<span class="special">}</span>
</pre>
<p>
If we are using the technique from the previous session,
<a href="techniques.html#python.creating_packages" title="Creating Packages">Creating Packages</a>, we can code directly
into <tt class="literal">geom/__init__.py</tt>:</p>
If we are using the technique from the previous session, <a href="techniques.html#python.creating_packages" title="Creating Packages">Creating
Packages</a>, we can code directly into <tt class="literal">geom/__init__.py</tt>:
</p>
<p></p>
<pre class="programlisting"><tt class="literal"><span class="keyword">from</span><span class="identifier"> _geom</span><span class="keyword"> import</span><span class="special"> *</span><span class="comment">
<pre class="programlisting">
<span class="keyword">from</span> <span class="identifier">_geom</span> <span class="keyword">import</span> <span class="special">*</span>
# a regular function
</span><span class="keyword">def</span><span class="identifier"> point_str</span><span class="special">(</span><span class="identifier">self</span><span class="special">):</span><span class="keyword">
return</span><span class="identifier"> str</span><span class="special">((</span><span class="identifier">self</span><span class="special">.</span><span class="identifier">x</span><span class="special">,</span><span class="identifier"> self</span><span class="special">.</span><span class="identifier">y</span><span class="special">))</span><span class="comment">
<span class="comment"># a regular function
</span><span class="keyword">def</span> <span class="identifier">point_str</span><span class="special">(</span><span class="identifier">self</span><span class="special">):</span>
<span class="keyword">return</span> <span class="identifier">str</span><span class="special">((</span><span class="identifier">self</span><span class="special">.</span><span class="identifier">x</span><span class="special">,</span> <span class="identifier">self</span><span class="special">.</span><span class="identifier">y</span><span class="special">))</span>
# now we turn it into a member function
</span><span class="identifier">point</span><span class="special">.</span><span class="identifier">__str__</span><span class="special"> =</span><span class="identifier"> point_str</span></tt></pre>
<p><span class="bold"><b>All</b></span> point instances created from C++ will also have this member function!
This technique has several advantages:</p>
<span class="comment"># now we turn it into a member function
</span><span class="identifier">point</span><span class="special">.</span><span class="identifier">__str__</span> <span class="special">=</span> <span class="identifier">point_str</span>
</pre>
<p><span class="bold"><b>All</b></span> point instances created from C++ will
also have this member function! This technique has several advantages:
</p>
<div class="itemizedlist"><ul type="disc">
<li>
Cut down compile times to zero for these additional functions
</li>
Cut down compile times to zero for these additional functions
</li>
<li>
Reduce the memory footprint to virtually zero
</li>
Reduce the memory footprint to virtually zero
</li>
<li>
Minimize the need to recompile
</li>
Minimize the need to recompile
</li>
<li>
Rapid prototyping (you can move the code to C++ if required without changing the interface)
</li>
Rapid prototyping (you can move the code to C++ if required without changing
the interface)
</li>
</ul></div>
<p>
You can even add a little syntactic sugar with the use of metaclasses. Let's
create a special metaclass that "injects" methods in other classes.</p>
<pre class="programlisting"><tt class="literal"><span class="comment"># The one Boost.Python uses for all wrapped classes.
# You can use here any class exported by Boost instead of "point"
</span><span class="identifier">BoostPythonMetaclass</span><span class="special"> =</span><span class="identifier"> point</span><span class="special">.</span><span class="identifier">__class__</span><span class="keyword">
You can even add a little syntactic sugar with the use of metaclasses. Let's
create a special metaclass that "injects" methods in other classes.
</p>
<pre class="programlisting">
<span class="comment"># The one Boost.Python uses for all wrapped classes.
</span><span class="comment"># You can use here any class exported by Boost instead of "point"
</span><span class="identifier">BoostPythonMetaclass</span> <span class="special">=</span> <span class="identifier">point</span><span class="special">.</span><span class="identifier">__class__</span>
class</span><span class="identifier"> injector</span><span class="special">(</span><span class="identifier">object</span><span class="special">):</span><span class="keyword">
class</span><span class="identifier"> __metaclass__</span><span class="special">(</span><span class="identifier">BoostPythonMetaclass</span><span class="special">):</span><span class="keyword">
def</span><span class="identifier"> __init__</span><span class="special">(</span><span class="identifier">self</span><span class="special">,</span><span class="identifier"> name</span><span class="special">,</span><span class="identifier"> bases</span><span class="special">,</span><span class="identifier"> dict</span><span class="special">):</span><span class="keyword">
for</span><span class="identifier"> b</span><span class="keyword"> in</span><span class="identifier"> bases</span><span class="special">:</span><span class="keyword">
if</span><span class="identifier"> type</span><span class="special">(</span><span class="identifier">b</span><span class="special">)</span><span class="keyword"> not</span><span class="keyword"> in</span><span class="special"> (</span><span class="identifier">self</span><span class="special">,</span><span class="identifier"> type</span><span class="special">):</span><span class="keyword">
for</span><span class="identifier"> k</span><span class="special">,</span><span class="identifier">v</span><span class="keyword"> in</span><span class="identifier"> dict</span><span class="special">.</span><span class="identifier">items</span><span class="special">():</span><span class="identifier">
setattr</span><span class="special">(</span><span class="identifier">b</span><span class="special">,</span><span class="identifier">k</span><span class="special">,</span><span class="identifier">v</span><span class="special">)</span><span class="keyword">
return</span><span class="identifier"> type</span><span class="special">.</span><span class="identifier">__init__</span><span class="special">(</span><span class="identifier">self</span><span class="special">,</span><span class="identifier"> name</span><span class="special">,</span><span class="identifier"> bases</span><span class="special">,</span><span class="identifier"> dict</span><span class="special">)</span><span class="comment">
<span class="keyword">class</span> <span class="identifier">injector</span><span class="special">(</span><span class="identifier">object</span><span class="special">):</span>
<span class="keyword">class</span> <span class="identifier">__metaclass__</span><span class="special">(</span><span class="identifier">BoostPythonMetaclass</span><span class="special">):</span>
<span class="keyword">def</span> <span class="identifier">__init__</span><span class="special">(</span><span class="identifier">self</span><span class="special">,</span> <span class="identifier">name</span><span class="special">,</span> <span class="identifier">bases</span><span class="special">,</span> <span class="identifier">dict</span><span class="special">):</span>
<span class="keyword">for</span> <span class="identifier">b</span> <span class="keyword">in</span> <span class="identifier">bases</span><span class="special">:</span>
<span class="keyword">if</span> <span class="identifier">type</span><span class="special">(</span><span class="identifier">b</span><span class="special">)</span> <span class="keyword">not</span> <span class="keyword">in</span> <span class="special">(</span><span class="identifier">self</span><span class="special">,</span> <span class="identifier">type</span><span class="special">):</span>
<span class="keyword">for</span> <span class="identifier">k</span><span class="special">,</span><span class="identifier">v</span> <span class="keyword">in</span> <span class="identifier">dict</span><span class="special">.</span><span class="identifier">items</span><span class="special">():</span>
<span class="identifier">setattr</span><span class="special">(</span><span class="identifier">b</span><span class="special">,</span><span class="identifier">k</span><span class="special">,</span><span class="identifier">v</span><span class="special">)</span>
<span class="keyword">return</span> <span class="identifier">type</span><span class="special">.</span><span class="identifier">__init__</span><span class="special">(</span><span class="identifier">self</span><span class="special">,</span> <span class="identifier">name</span><span class="special">,</span> <span class="identifier">bases</span><span class="special">,</span> <span class="identifier">dict</span><span class="special">)</span>
# inject some methods in the point foo
</span><span class="keyword">class</span><span class="identifier"> more_point</span><span class="special">(</span><span class="identifier">injector</span><span class="special">,</span><span class="identifier"> point</span><span class="special">):</span><span class="keyword">
def</span><span class="identifier"> __repr__</span><span class="special">(</span><span class="identifier">self</span><span class="special">):</span><span class="keyword">
return</span><span class="string"> 'Point(x=%s, y=%s)'</span><span class="special"> %</span><span class="special"> (</span><span class="identifier">self</span><span class="special">.</span><span class="identifier">x</span><span class="special">,</span><span class="identifier"> self</span><span class="special">.</span><span class="identifier">y</span><span class="special">)</span><span class="keyword">
def</span><span class="identifier"> foo</span><span class="special">(</span><span class="identifier">self</span><span class="special">):</span><span class="keyword">
print</span><span class="string"> 'foo!'</span></tt></pre>
<span class="comment"># inject some methods in the point foo
</span><span class="keyword">class</span> <span class="identifier">more_point</span><span class="special">(</span><span class="identifier">injector</span><span class="special">,</span> <span class="identifier">point</span><span class="special">):</span>
<span class="keyword">def</span> <span class="identifier">__repr__</span><span class="special">(</span><span class="identifier">self</span><span class="special">):</span>
<span class="keyword">return</span> <span class="string">'Point(x=%s, y=%s)'</span> <span class="special">%</span> <span class="special">(</span><span class="identifier">self</span><span class="special">.</span><span class="identifier">x</span><span class="special">,</span> <span class="identifier">self</span><span class="special">.</span><span class="identifier">y</span><span class="special">)</span>
<span class="keyword">def</span> <span class="identifier">foo</span><span class="special">(</span><span class="identifier">self</span><span class="special">):</span>
<span class="keyword">print</span> <span class="string">'foo!'</span>
</pre>
<p>
Now let's see how it got:</p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="keyword"> print</span><span class="identifier"> point</span><span class="special">()</span><span class="identifier">
Point</span><span class="special">(</span><span class="identifier">x</span><span class="special">=</span><span class="number">10</span><span class="special">,</span><span class="identifier"> y</span><span class="special">=</span><span class="number">10</span><span class="special">)</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> point</span><span class="special">().</span><span class="identifier">foo</span><span class="special">()</span><span class="identifier">
foo</span><span class="special">!</span></tt></pre>
Now let's see how it got:
</p>
<pre class="programlisting">
<span class="special">&gt;&gt;&gt;</span> <span class="keyword">print</span> <span class="identifier">point</span><span class="special">()</span>
<span class="identifier">Point</span><span class="special">(</span><span class="identifier">x</span><span class="special">=</span><span class="number">10</span><span class="special">,</span> <span class="identifier">y</span><span class="special">=</span><span class="number">10</span><span class="special">)</span>
<span class="special">&gt;&gt;&gt;</span> <span class="identifier">point</span><span class="special">().</span><span class="identifier">foo</span><span class="special">()</span>
<span class="identifier">foo</span><span class="special">!</span>
</pre>
<p>
Another useful idea is to replace constructors with factory functions:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">_point</span><span class="special"> =</span><span class="identifier"> point</span><span class="keyword">
Another useful idea is to replace constructors with factory functions:
</p>
<pre class="programlisting">
<span class="identifier">_point</span> <span class="special">=</span> <span class="identifier">point</span>
def</span><span class="identifier"> point</span><span class="special">(</span><span class="identifier">x</span><span class="special">=</span><span class="number">0</span><span class="special">,</span><span class="identifier"> y</span><span class="special">=</span><span class="number">0</span><span class="special">):</span><span class="keyword">
return</span><span class="identifier"> _point</span><span class="special">(</span><span class="identifier">x</span><span class="special">,</span><span class="identifier"> y</span><span class="special">)</span></tt></pre>
<span class="keyword">def</span> <span class="identifier">point</span><span class="special">(</span><span class="identifier">x</span><span class="special">=</span><span class="number">0</span><span class="special">,</span> <span class="identifier">y</span><span class="special">=</span><span class="number">0</span><span class="special">):</span>
<span class="keyword">return</span> <span class="identifier">_point</span><span class="special">(</span><span class="identifier">x</span><span class="special">,</span> <span class="identifier">y</span><span class="special">)</span>
</pre>
<p>
In this simple case there is not much gained, but for constructurs with
many overloads and/or arguments this is often a great simplification, again
with virtually zero memory footprint and zero compile-time overhead for
the keyword support.</p>
In this simple case there is not much gained, but for constructurs with many
overloads and/or arguments this is often a great simplification, again with
virtually zero memory footprint and zero compile-time overhead for the keyword
support.
</p>
</div>
<div class="section" lang="en">
<div class="titlepage"><div><div><h3 class="title">
<a name="python.reducing_compiling_time"></a>Reducing Compiling Time</h3></div></div></div>
<p>
If you have ever exported a lot of classes, you know that it takes quite a good
time to compile the Boost.Python wrappers. Plus the memory consumption can
easily become too high. If this is causing you problems, you can split the
class_ definitions in multiple files:</p>
Reducing Compiling TimeIf you have ever exported a lot of classes, you know
that it takes quite a good time to compile the Boost.Python wrappers. Plus
the memory consumption can easily become too high. If this is causing you
problems, you can split the class_ definitions in multiple files:
</p>
<p></p>
<pre class="programlisting"><tt class="literal"><span class="comment">/* file point.cpp */</span><span class="preprocessor">
#include</span><span class="special"> &lt;</span><span class="identifier">point</span><span class="special">.</span><span class="identifier">h</span><span class="special">&gt;</span><span class="preprocessor">
#include</span><span class="special"> &lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">python</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span><span class="keyword">
<pre class="programlisting">
<span class="comment">/* file point.cpp */</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">point</span><span class="special">.</span><span class="identifier">h</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">python</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
void</span><span class="identifier"> export_point</span><span class="special">()</span><span class="special">
{</span><span class="identifier">
class_</span><span class="special">&lt;</span><span class="identifier">point</span><span class="special">&gt;(</span><span class="string">"point"</span><span class="special">)...;</span><span class="special">
}</span><span class="comment">
<span class="keyword">void</span> <span class="identifier">export_point</span><span class="special">()</span>
<span class="special">{</span>
<span class="identifier">class_</span><span class="special">&lt;</span><span class="identifier">point</span><span class="special">&gt;(</span><span class="string">"point"</span><span class="special">)...;</span>
<span class="special">}</span>
/* file triangle.cpp */</span><span class="preprocessor">
#include</span><span class="special"> &lt;</span><span class="identifier">triangle</span><span class="special">.</span><span class="identifier">h</span><span class="special">&gt;</span><span class="preprocessor">
#include</span><span class="special"> &lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">python</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span><span class="keyword">
<span class="comment">/* file triangle.cpp */</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">triangle</span><span class="special">.</span><span class="identifier">h</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">python</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
void</span><span class="identifier"> export_triangle</span><span class="special">()</span><span class="special">
{</span><span class="identifier">
class_</span><span class="special">&lt;</span><span class="identifier">triangle</span><span class="special">&gt;(</span><span class="string">"triangle"</span><span class="special">)...;</span><span class="special">
}</span></tt></pre>
<span class="keyword">void</span> <span class="identifier">export_triangle</span><span class="special">()</span>
<span class="special">{</span>
<span class="identifier">class_</span><span class="special">&lt;</span><span class="identifier">triangle</span><span class="special">&gt;(</span><span class="string">"triangle"</span><span class="special">)...;</span>
<span class="special">}</span>
</pre>
<p>
Now you create a file <tt class="literal">main.cpp</tt>, which contains the <tt class="literal">BOOST_PYTHON_MODULE</tt>
macro, and call the various export functions inside it.</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">void</span><span class="identifier"> export_point</span><span class="special">();</span><span class="keyword">
void</span><span class="identifier"> export_triangle</span><span class="special">();</span><span class="identifier">
Now you create a file <tt class="literal">main.cpp</tt>, which contains the <tt class="literal">BOOST_PYTHON_MODULE</tt>
macro, and call the various export functions inside it.
</p>
<pre class="programlisting">
<span class="keyword">void</span> <span class="identifier">export_point</span><span class="special">();</span>
<span class="keyword">void</span> <span class="identifier">export_triangle</span><span class="special">();</span>
BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">_geom</span><span class="special">)</span><span class="special">
{</span><span class="identifier">
export_point</span><span class="special">();</span><span class="identifier">
export_triangle</span><span class="special">();</span><span class="special">
}</span></tt></pre>
<span class="identifier">BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">_geom</span><span class="special">)</span>
<span class="special">{</span>
<span class="identifier">export_point</span><span class="special">();</span>
<span class="identifier">export_triangle</span><span class="special">();</span>
<span class="special">}</span>
</pre>
<p>
Compiling and linking together all this files produces the same result as the
usual approach:</p>
<pre class="programlisting"><tt class="literal"><span class="preprocessor">#include</span><span class="special"> &lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">python</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span><span class="preprocessor">
#include</span><span class="special"> &lt;</span><span class="identifier">point</span><span class="special">.</span><span class="identifier">h</span><span class="special">&gt;</span><span class="preprocessor">
#include</span><span class="special"> &lt;</span><span class="identifier">triangle</span><span class="special">.</span><span class="identifier">h</span><span class="special">&gt;</span><span class="identifier">
Compiling and linking together all this files produces the same result as
the usual approach:
</p>
<pre class="programlisting">
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">python</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">point</span><span class="special">.</span><span class="identifier">h</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">triangle</span><span class="special">.</span><span class="identifier">h</span><span class="special">&gt;</span>
BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">_geom</span><span class="special">)</span><span class="special">
{</span><span class="identifier">
class_</span><span class="special">&lt;</span><span class="identifier">point</span><span class="special">&gt;(</span><span class="string">"point"</span><span class="special">)...;</span><span class="identifier">
class_</span><span class="special">&lt;</span><span class="identifier">triangle</span><span class="special">&gt;(</span><span class="string">"triangle"</span><span class="special">)...;</span><span class="special">
}</span></tt></pre>
<span class="identifier">BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">_geom</span><span class="special">)</span>
<span class="special">{</span>
<span class="identifier">class_</span><span class="special">&lt;</span><span class="identifier">point</span><span class="special">&gt;(</span><span class="string">"point"</span><span class="special">)...;</span>
<span class="identifier">class_</span><span class="special">&lt;</span><span class="identifier">triangle</span><span class="special">&gt;(</span><span class="string">"triangle"</span><span class="special">)...;</span>
<span class="special">}</span>
</pre>
<p>
but the memory is kept under control.</p>
but the memory is kept under control.
</p>
<p>
This method is recommended too if you are developing the C++ library and
exporting it to Python at the same time: changes in a class will only demand
the compilation of a single cpp, instead of the entire wrapper code.</p>
This method is recommended too if you are developing the C++ library and
exporting it to Python at the same time: changes in a class will only demand
the compilation of a single cpp, instead of the entire wrapper code.
</p>
<div class="informaltable"><table class="table">
<colgroup><col></colgroup>
<tbody><tr><td class="blurb">
<span class="inlinemediaobject"><img src="../images/note.png"></span> If you're exporting your classes with <a href="../../../../../pyste/index.html" target="_top">Pyste</a>,
take a look at the <tt class="literal">--multiple</tt> option, that generates the wrappers in
various files as demonstrated here.</td></tr></tbody>
<span class="inlinemediaobject"><img src="../images/note.png"></span>
If you're exporting your classes with <a href="../../../../../pyste/index.html" target="_top">Pyste</a>,
take a look at the <tt class="literal">--multiple</tt> option, that generates
the wrappers in various files as demonstrated here.</td></tr></tbody>
</table></div>
<div class="informaltable"><table class="table">
<colgroup><col></colgroup>
<tbody><tr><td class="blurb">
<span class="inlinemediaobject"><img src="../images/note.png"></span> This method is useful too if you are getting the error message
<span class="emphasis"><em>"fatal error C1204:Compiler limit:internal structure overflow"</em></span> when compiling
a large source file, as explained in the <a href="../../../../v2/faq.html#c1204" target="_top">FAQ</a>.</td></tr></tbody>
<span class="inlinemediaobject"><img src="../images/note.png"></span>
This method is useful too if you are getting the error message <span class="emphasis"><em>"fatal
error C1204:Compiler limit:internal structure overflow"</em></span>
when compiling a large source file, as explained in the <a href="../../../../v2/faq.html#c1204" target="_top">FAQ</a>.</td></tr></tbody>
</table></div>
</div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><small>Copyright © 2002-2005 Joel de Guzman, David Abrahams</small></td>
<td align="right"><small>Copyright © 2002-2005 Joel
de Guzman, David Abrahams</small></td>
</tr></table>
<hr>
<div class="spirit-nav">

View File

@ -1754,6 +1754,38 @@ Now, our C++ Wrapper:
.property("pions", range(&F::p_begin, &F::p_end))
.property("bogons", range(&F::b_begin, &F::b_end));
[*stl_input_iterator]
So far, we have seen how to expose C++ iterators and ranges to Python.
Sometimes we wish to go the other way, though: we'd like to pass a
Python sequence to an STL algorithm or use it to initialize an STL
container. We need to make a Python iterator look like an STL iterator.
For that, we use `stl_input_iterator<>`. Consider how we might
implement a function that exposes `std::list<int>::assign()` to
Python:
[c++]
template<typename T>
void list_assign(std::list<T>& l, object o) {
// Turn a Python sequence into an STL input range
stl_input_iterator<T> begin(o), end;
l.assign(begin, end);
}
// Part of the wrapper for list<int>
class_<std::list<int> >("list_int")
.def("assign", &list_assign<int>)
// ...
;
Now in Python, we can assign any integer sequence to `list_int` objects:
[python]
x = list_int();
x.assign([1,2,3,4,5])
[endsect]
[section:exception Exception Translation]

View File

@ -293,6 +293,20 @@
</dl>
</dd>
<dt><a href="stl_iterator.html">stl_iterator.hpp</a></dt>
<dd>
<dl class="index">
<dt><a href="stl_iterator.html#classes">Classes</a></dt>
<dd>
<dl class="index">
<dt><a href="stl_iterator.html#stl_input_iterator-spec">stl_input_iterator</a></dt>
</dl>
</dd>
</dl>
</dd>
<dt><a href="wrapper.html">wrapper.hpp</a></dt>
<dd>

269
doc/v2/stl_iterator.html Executable file
View File

@ -0,0 +1,269 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Boost.Python - &lt;boost/python/stl_iterator.hpp&gt;</title>
<meta name="generator" content=
"HTML Tidy for Windows (vers 1st August 2002), see www.w3.org" >
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<link rel="stylesheet" type="text/css" href="../boost.css">
</head>
<body>
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
header >
<tr>
<td valign="top" width="300">
<h3><a href="../../../../index.htm"><img height="86" width="277"
alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3>
</td>
<td valign="top">
<h1 align="center"><a href="../index.html">Boost.Python</a></h1>
<h2 align="center">Header &lt;boost/python/stl_iterator.hpp&gt;</h2>
</td>
</tr>
</table>
<hr>
<h2>Contents</h2>
<dl class="page-index">
<dt><a href="#introduction">Introduction</a></dt>
<dt><a href="#classes">Classes</a></dt>
<dd>
<dl class="page-index">
<dt><a href="#stl_input_iterator-spec">Class template
<code>stl_input_iterator</code></a></dt>
<dd>
<dl class="page-index">
<dt><a href="#stl_input_iterator-spec-synopsis">Class
<code>stl_input_iterator</code> synopsis</a></dt>
<dt><a href="#stl_input_iterator-spec-constructors">Class template
<code>stl_input_iterator</code> constructors</a></dt>
<dt><a href="#stl_input_iterator-spec-modifiers">Class template
<code>stl_input_iterator</code> modifiers</a></dt>
<dt><a href="#stl_input_iterator-spec-observers">Class template
<code>stl_input_iterator</code> observers</a></dt>
</dl>
</dd>
</dl>
</dd>
<dt><a href="#examples">Examples</a></dt>
</dl>
<hr>
<h2><a name="introduction"></a>Introduction</h2>
<p><code>&lt;boost/python/stl_iterator.hpp&gt;</code> provides types
for creating <a href="http://www.sgi.com/tech/stl/Iterators.html">C++
Iterators</a> from <a href="http://www.python.org/doc/current/lib/typesseq.html">
Python sequences</a>.</p>
<h2><a name="classes"></a>Classes</h2>
<h3><a name="stl_input_iterator-spec"></a>Class Template
<code>stl_input_iterator</code></h3>
<p>Instances of <code>stl_input_iterator&lt;T&gt;</code> hold a Python
iterator and adapt it for use with STL algorithms.
<code>stl_input_iterator&lt;T&gt;</code> satisfies the requirements for
an <a href="http://www.sgi.com/tech/stl/InputIterator.html">Input Iterator</a>.
</p>
<table border="1" summary="stl_input_iterator template parameters">
<tr>
<th>Template Parameter</th>
<th>Requirements</th>
<th>Semantics</th>
<th>Default</th>
</tr>
<tr>
<td><code>ValueType</code></td>
<td><code>ValueType</code> must be CopyConstructible.</td>
<td>Dereferencing an instance of <code>stl_input_iterator&lt;ValueType&gt;</code>
will return an rvalue of type <code>ValueType</code>.</td>
<td><i>None</i></td>
</tr>
</table>
<h4><a name="stl_input_iterator-spec-synopsis"></a>Class Template stl_input_iterator
synopsis</h4>
<pre>
namespace boost { namespace python
{
template &lt;class ValueType&gt;
struct stl_input_iterator
{
stl_input_iterator();
stl_input_iterator(<a href="object.html#object-spec">object</a> const&amp; ob);
stl_input_iterator&amp; operator++();
stl_input_iterator operator++(int);
ValueType operator*() const;
friend bool operator==(stl_input_iterator const&amp; lhs, stl_input_iterator const&amp; rhs);
friend bool operator!=(stl_input_iterator const&amp; lhs, stl_input_iterator const&amp; rhs);
private:
<a href="object.html#object-spec">object</a> it_; // For exposition only
<a href="object.html#object-spec">object</a> ob_; // For exposition only
};
}}
</pre>
<h4>
<a name="stl_input_iterator-spec-constructors"></a>Class Template <code>stl_input_iterator</code>
constructors
</h4>
<pre>
stl_input_iterator()
</pre>
<dl class="function-semantics">
<dt><b>Effects:</b>
Creates a past-the-end input iterator, useful for signifying the end of a sequence.
</dt>
<dt><b>Postconditions:</b> <code>this</code> is past-the-end.</dt>
<dt><b>Throws:</b> Nothing.</dt>
</dl>
<pre>
stl_input_iterator(object const&amp; ob)
</pre>
<dl class="function-semantics">
<dt><b>Effects:</b>
Calls <code>ob.attr("__iter__")()</code> and stores the resulting Python iterator
object in <code>this-&gt;it_</code>. Then, calls <code>this-&gt;it_.attr("next")()</code> and
stores the result in <code>this-&gt;ob_</code>. If the sequence is exhausted, sets
<code>this-&gt;ob_</code> to <code>object()</code>.
</dt>
<dt><b>Postconditions:</b> <code>this</code> is a dereferenceable or past-the-end.</dt>
<dt><b>Throws:</b> <code>error_already_set</code> if <code>ob</code> does not
provide an iterator.</dt>
</dl>
<h4>
<a name="stl_input_iterator-spec-modifiers"></a>Class Template <code>stl_input_iterator</code>
modifiers
</h4>
<pre>
stl_input_iterator&amp; operator++()
</pre>
<dl class="function-semantics">
<dt><b>Effects:</b>
Calls <code>this-&gt;it_.attr("next")()</code> and stores the result in
<code>this-&gt;ob_</code>. If the sequence is exhausted, sets <code>this-&gt;ob_</code>
to <code>object()</code>.
</dt>
<dt><b>Postconditions:</b> <code>this</code> is a dereferenceable or past-the-end.</dt>
<dt><b>Returns:</b> <code>*this</code>.</dt>
</dl>
<pre>
stl_input_iterator operator++(int)
</pre>
<dl class="function-semantics">
<dt><b>Effects:</b>
<code>stl_input_iterator tmp = *this; ++*this; return tmp;</code>
</dt>
<dt><b>Postconditions:</b> <code>this</code> is a dereferenceable or past-the-end.</dt>
</dl>
<h4><a name="stl_input_iterator-spec-observers"></a>Class Template<code>stl_input_iterator</code>
observers</h4>
<pre>
ValueType operator*() const
</pre>
<dl class="function-semantics">
<dt><b>Effects:</b>
Returns the current element in the sequence.
</dt>
<dt><b>Returns:</b>
<code>extract&lt;ValueType&gt;(this-&gt;ob_);</code>
</dt>
<dt><b>Throws:</b> <code>error_already_set</code> if the current element in the sequence
is not of type <code>ValueType</code>.</dt>
</dl>
<pre>
friend bool operator==(stl_input_iterator const&amp; lhs, stl_input_iterator const&amp; rhs)
</pre>
<dl class="function-semantics">
<dt><b>Effects:</b>
Returns true if both iterators are dereferenceable or if both iterators are past-the-end,
false otherwise.
</dt>
<dt><b>Returns:</b>
<code>(lhs.ob_ == object()) == (rhs.ob_ == object())</code>
</dt>
</dl>
<pre>
friend bool operator!=(stl_input_iterator const&amp; lhs, stl_input_iterator const&amp; rhs)
</pre>
<dl class="function-semantics">
<dt><b>Effects:</b>
Returns false if both iterators are dereferenceable or if both iterators are past-the-end,
true otherwise.
</dt>
<dt><b>Returns:</b>
<code>!(lhs == rhs)</code>
</dt>
</dl>
<h2><a name="examples"></a>Examples</h2>
<pre>
#include &lt;boost/python/object.hpp&gt;
#include &lt;boost/python/stl_iterator.hpp&gt;
#include &lt;list&gt;
using namespace boost::python;
std::list&lt;int&gt; sequence_to_int_list(object const&amp; ob)
{
stl_input_iterator&lt;int&gt; begin(ob), end;
return std::list&lt;int&gt;(begin, end);
}
</pre>
<hr>
<p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->30
October, 2005
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p>
<p><i>© Copyright Eric Niebler 2005.</i></p>
</body>
</html>

42
src/object/stl_iterator.cpp Executable file
View File

@ -0,0 +1,42 @@
// Copyright Eric Niebler 2005.
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/python/object.hpp>
#include <boost/python/handle.hpp>
#include <boost/python/object/stl_iterator_core.hpp>
namespace boost { namespace python { namespace objects
{
stl_input_iterator_impl::stl_input_iterator_impl()
: it_()
, ob_()
{
}
stl_input_iterator_impl::stl_input_iterator_impl(boost::python::object const &ob)
: it_(ob.attr("__iter__")())
, ob_()
{
this->increment();
}
void stl_input_iterator_impl::increment()
{
this->ob_ = boost::python::handle<>(
boost::python::allow_null(PyIter_Next(this->it_.ptr())));
}
bool stl_input_iterator_impl::equal(stl_input_iterator_impl const &that) const
{
return !this->ob_ == !that.ob_;
}
boost::python::handle<> const &stl_input_iterator_impl::current() const
{
return this->ob_;
}
}}} // namespace boost::python::objects

View File

@ -152,6 +152,8 @@ bpl-test crossmod_exception
[ bpl-test iterator : iterator.py iterator.cpp input_iterator.cpp ]
[ bpl-test stl_iterator : stl_iterator.py stl_iterator.cpp ]
[ bpl-test extract ]
[ bpl-test opaque ]

View File

@ -101,6 +101,8 @@ bpl-test crossmod_exception
#
[ bpl-test iterator : iterator.py iterator.cpp input_iterator.cpp ]
[ bpl-test stl_iterator : stl_iterator.py stl_iterator.cpp ]
[ bpl-test extract ]
[ bpl-test opaque ]

31
test/stl_iterator.cpp Executable file
View File

@ -0,0 +1,31 @@
// Copyright Eric Niebler 2005.
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <list>
#include <boost/python/module.hpp>
#include <boost/python/def.hpp>
#include <boost/python/iterator.hpp>
#include <boost/python/stl_iterator.hpp>
using namespace boost::python;
typedef std::list<int> list_int;
void assign(list_int& x, object const& y)
{
stl_input_iterator<int> begin(y), end;
x.assign(begin, end);
}
BOOST_PYTHON_MODULE(stl_iterator_ext)
{
using boost::python::iterator; // gcc 2.96 bug workaround
class_<list_int>("list_int")
.def("assign", assign)
.def("__iter__", iterator<list_int>())
;
}
#include "module_tail.cpp"

29
test/stl_iterator.py Normal file
View File

@ -0,0 +1,29 @@
# Copyright Eric Niebler 2005. Distributed under the Boost
# Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
'''
>>> from stl_iterator_ext import *
>>> x = list_int()
>>> x.assign([1,2,3,4,5])
>>> for y in x:
... print y
1
2
3
4
5
'''
def run(args = None):
import sys
import doctest
if args is not None:
sys.argv = args
return doctest.testmod(sys.modules.get(__name__))
if __name__ == '__main__':
print "running..."
import sys
status = run()[0]
if (status == 0): print "Done."
sys.exit(status)