diff options
Diffstat (limited to 'libs/python/doc/tutorial')
22 files changed, 4854 insertions, 0 deletions
diff --git a/libs/python/doc/tutorial/doc/Jamfile.v2 b/libs/python/doc/tutorial/doc/Jamfile.v2 new file mode 100644 index 000000000..ba8882636 --- /dev/null +++ b/libs/python/doc/tutorial/doc/Jamfile.v2 @@ -0,0 +1,18 @@ +# Copyright Joel de Guzman 2006. 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) +project boost/libs/python/doc/tutorial/doc ; + +import boostbook : boostbook ; +using quickbook ; + +path-constant images : html ; + +boostbook tutorial + : + tutorial.qbk + : + <xsl:param>boost.root=../../../../../.. + <format>pdf:<xsl:param>img.src.path=$(images)/ + <format>pdf:<xsl:param>boost.url.prefix=http://www.boost.org/doc/libs/release/libs/python/doc/tutorial/doc/html + ; diff --git a/libs/python/doc/tutorial/doc/html/images/alert.png b/libs/python/doc/tutorial/doc/html/images/alert.png Binary files differnew file mode 100644 index 000000000..b4645bc7e --- /dev/null +++ b/libs/python/doc/tutorial/doc/html/images/alert.png diff --git a/libs/python/doc/tutorial/doc/html/images/home.png b/libs/python/doc/tutorial/doc/html/images/home.png Binary files differnew file mode 100644 index 000000000..5584aacb0 --- /dev/null +++ b/libs/python/doc/tutorial/doc/html/images/home.png diff --git a/libs/python/doc/tutorial/doc/html/images/jam.png b/libs/python/doc/tutorial/doc/html/images/jam.png Binary files differnew file mode 100644 index 000000000..224ed7914 --- /dev/null +++ b/libs/python/doc/tutorial/doc/html/images/jam.png diff --git a/libs/python/doc/tutorial/doc/html/images/next.png b/libs/python/doc/tutorial/doc/html/images/next.png Binary files differnew file mode 100644 index 000000000..59800b4e8 --- /dev/null +++ b/libs/python/doc/tutorial/doc/html/images/next.png diff --git a/libs/python/doc/tutorial/doc/html/images/note.png b/libs/python/doc/tutorial/doc/html/images/note.png Binary files differnew file mode 100644 index 000000000..3ed047cac --- /dev/null +++ b/libs/python/doc/tutorial/doc/html/images/note.png diff --git a/libs/python/doc/tutorial/doc/html/images/prev.png b/libs/python/doc/tutorial/doc/html/images/prev.png Binary files differnew file mode 100644 index 000000000..d88a40f92 --- /dev/null +++ b/libs/python/doc/tutorial/doc/html/images/prev.png diff --git a/libs/python/doc/tutorial/doc/html/images/python.png b/libs/python/doc/tutorial/doc/html/images/python.png Binary files differnew file mode 100644 index 000000000..cc2ff1d54 --- /dev/null +++ b/libs/python/doc/tutorial/doc/html/images/python.png diff --git a/libs/python/doc/tutorial/doc/html/images/smiley.png b/libs/python/doc/tutorial/doc/html/images/smiley.png Binary files differnew file mode 100644 index 000000000..30a77f71c --- /dev/null +++ b/libs/python/doc/tutorial/doc/html/images/smiley.png diff --git a/libs/python/doc/tutorial/doc/html/images/tip.png b/libs/python/doc/tutorial/doc/html/images/tip.png Binary files differnew file mode 100644 index 000000000..9f596b0b8 --- /dev/null +++ b/libs/python/doc/tutorial/doc/html/images/tip.png diff --git a/libs/python/doc/tutorial/doc/html/images/up.png b/libs/python/doc/tutorial/doc/html/images/up.png Binary files differnew file mode 100644 index 000000000..17d9c3ec4 --- /dev/null +++ b/libs/python/doc/tutorial/doc/html/images/up.png diff --git a/libs/python/doc/tutorial/doc/html/index.html b/libs/python/doc/tutorial/doc/html/index.html new file mode 100644 index 000000000..c324f065c --- /dev/null +++ b/libs/python/doc/tutorial/doc/html/index.html @@ -0,0 +1,142 @@ +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII"> +<title>Chapter 1. python 2.0</title> +<link rel="stylesheet" href="../../../../../../doc/src/boostbook.css" type="text/css"> +<meta name="generator" content="DocBook XSL Stylesheets V1.76.1"> +<link rel="home" href="index.html" title="Chapter 1. python 2.0"> +<link rel="next" href="python/hello.html" title="Building Hello World"> +</head> +<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"> +<table cellpadding="2" width="100%"><tr> +<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../boost.png"></td> +<td align="center"><a href="../../../../../../index.html">Home</a></td> +<td align="center"><a href="../../../../../../libs/libraries.htm">Libraries</a></td> +<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td> +<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td> +<td align="center"><a href="../../../../../../more/index.htm">More</a></td> +</tr></table> +<hr> +<div class="spirit-nav"><a accesskey="n" href="python/hello.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a></div> +<div class="chapter"> +<div class="titlepage"><div> +<div><h2 class="title"> +<a name="python"></a>Chapter 1. python 2.0</h2></div> +<div><div class="author"><h3 class="author"> +<span class="firstname">Joel</span> <span class="surname">de Guzman</span> +</h3></div></div> +<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><div class="legalnotice"> +<a name="python.legal"></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> +<div class="toc"> +<p><b>Table of Contents</b></p> +<dl> +<dt><span class="section"><a href="index.html#python.quickstart">QuickStart</a></span></dt> +<dt><span class="section"><a href="python/hello.html">Building Hello World</a></span></dt> +<dt><span class="section"><a href="python/exposing.html">Exposing Classes</a></span></dt> +<dd><dl> +<dt><span class="section"><a href="python/exposing.html#python.constructors">Constructors</a></span></dt> +<dt><span class="section"><a href="python/exposing.html#python.class_data_members">Class Data Members</a></span></dt> +<dt><span class="section"><a href="python/exposing.html#python.class_properties">Class Properties</a></span></dt> +<dt><span class="section"><a href="python/exposing.html#python.inheritance">Inheritance</a></span></dt> +<dt><span class="section"><a href="python/exposing.html#python.class_virtual_functions">Class Virtual Functions</a></span></dt> +<dt><span class="section"><a href="python/exposing.html#python.virtual_functions_with_default_implementations">Virtual Functions with Default Implementations</a></span></dt> +<dt><span class="section"><a href="python/exposing.html#python.class_operators_special_functions">Class Operators/Special Functions</a></span></dt> +</dl></dd> +<dt><span class="section"><a href="python/functions.html">Functions</a></span></dt> +<dd><dl> +<dt><span class="section"><a href="python/functions.html#python.call_policies">Call Policies</a></span></dt> +<dt><span class="section"><a href="python/functions.html#python.overloading">Overloading</a></span></dt> +<dt><span class="section"><a href="python/functions.html#python.default_arguments">Default Arguments</a></span></dt> +<dt><span class="section"><a href="python/functions.html#python.auto_overloading">Auto-Overloading</a></span></dt> +</dl></dd> +<dt><span class="section"><a href="python/object.html">Object Interface</a></span></dt> +<dd><dl> +<dt><span class="section"><a href="python/object.html#python.basic_interface">Basic Interface</a></span></dt> +<dt><span class="section"><a href="python/object.html#python.derived_object_types">Derived Object types</a></span></dt> +<dt><span class="section"><a href="python/object.html#python.extracting_c___objects">Extracting C++ objects</a></span></dt> +<dt><span class="section"><a href="python/object.html#python.enums">Enums</a></span></dt> +<dt><span class="section"><a href="python/object.html#python.creating_python_object">Creating <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">python</span><span class="special">::</span><span class="identifier">object</span></code> from <code class="computeroutput"><span class="identifier">PyObject</span><span class="special">*</span></code></a></span></dt> +</dl></dd> +<dt><span class="section"><a href="python/embedding.html">Embedding</a></span></dt> +<dd><dl><dt><span class="section"><a href="python/embedding.html#python.using_the_interpreter">Using the interpreter</a></span></dt></dl></dd> +<dt><span class="section"><a href="python/iterators.html">Iterators</a></span></dt> +<dt><span class="section"><a href="python/exception.html">Exception Translation</a></span></dt> +<dt><span class="section"><a href="python/techniques.html">General Techniques</a></span></dt> +<dd><dl> +<dt><span class="section"><a href="python/techniques.html#python.creating_packages">Creating Packages</a></span></dt> +<dt><span class="section"><a href="python/techniques.html#python.extending_wrapped_objects_in_python">Extending Wrapped Objects in Python</a></span></dt> +<dt><span class="section"><a href="python/techniques.html#python.reducing_compiling_time">Reducing Compiling Time</a></span></dt> +</dl></dd> +</dl> +</div> +<div class="section"> +<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> +<h3> +<a name="quickstart.hello_world"></a> + Hello World + </h3> +<p> + 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"><span class="preprocessor">#include</span> <span class="special"><</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">></span> + +<span class="identifier">BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">hello_ext</span><span class="special">)</span> +<span class="special">{</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">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> +<pre class="programlisting"><span class="special">>>></span> <span class="keyword">import</span> <span class="identifier">hello_ext</span> +<span class="special">>>></span> <span class="keyword">print</span> <span class="identifier">hello_ext</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> +<div class="blockquote"><blockquote class="blockquote"><p> + <span class="emphasis"><em><span class="bold"><strong>Next stop... Building your Hello World module + from start to finish...</strong></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"><p><small>Last revised: December 26, 2011 at 21:58:39 GMT</small></p></td> +<td align="right"><div class="copyright-footer"></div></td> +</tr></table> +<hr> +<div class="spirit-nav"><a accesskey="n" href="python/hello.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a></div> +</body> +</html> diff --git a/libs/python/doc/tutorial/doc/html/python/embedding.html b/libs/python/doc/tutorial/doc/html/python/embedding.html new file mode 100644 index 000000000..4e1c21857 --- /dev/null +++ b/libs/python/doc/tutorial/doc/html/python/embedding.html @@ -0,0 +1,269 @@ +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII"> +<title>Embedding</title> +<link rel="stylesheet" href="../../../../../../../doc/src/boostbook.css" type="text/css"> +<meta name="generator" content="DocBook XSL Stylesheets V1.76.1"> +<link rel="home" href="../index.html" title="Chapter 1. python 2.0"> +<link rel="up" href="../index.html" title="Chapter 1. python 2.0"> +<link rel="prev" href="object.html" title="Object Interface"> +<link rel="next" href="iterators.html" title="Iterators"> +</head> +<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"> +<table cellpadding="2" width="100%"><tr> +<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../../boost.png"></td> +<td align="center"><a href="../../../../../../../index.html">Home</a></td> +<td align="center"><a href="../../../../../../../libs/libraries.htm">Libraries</a></td> +<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td> +<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td> +<td align="center"><a href="../../../../../../../more/index.htm">More</a></td> +</tr></table> +<hr> +<div class="spirit-nav"> +<a accesskey="p" href="object.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="iterators.html"><img src="../../../../../../../doc/src/images/next.png" alt="Next"></a> +</div> +<div class="section"> +<div class="titlepage"><div><div><h2 class="title" style="clear: both"> +<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> +<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" alt="smiley"></span> + </p> +<h3> +<a name="embedding.building_embedded_programs"></a> + Building embedded programs + </h3> +<p> + To be able to embed python into your programs, you have to link to both Boost.Python's + as well as Python's own runtime library. + </p> +<p> + Boost.Python's library comes in two variants. Both are located in Boost's + <code class="literal">/libs/python/build/bin-stage</code> subdirectory. On Windows, the + variants are called <code class="literal">boost_python.lib</code> (for release builds) + and <code class="literal">boost_python_debug.lib</code> (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 library can be found in the <code class="literal">/libs</code> 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 <code class="literal">/include</code> subdirectory has to be added + to your include path. + </p> +<p> + 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) ; +include python.jam ; + +exe embedded_program # name of the executable + : #sources + embedded_program.cpp + : # requirements + <find-library>boost_python <library-path>c:\boost\libs\python + $(PYTHON_PROPERTIES) + <library-path>$(PYTHON_LIB_PATH) + <find-library>$(PYTHON_EMBEDDED_LIBRARY) ; +</pre> +<h3> +<a name="embedding.getting_started"></a> + Getting started + </h3> +<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 class="orderedlist" type="1"> +<li class="listitem"> + #include <code class="literal"><boost/python.hpp></code> + </li> +<li class="listitem"> + 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 <code class="literal">__main__</code> module. + </li> +<li class="listitem"> + Call other Python C API routines to use the interpreter. + </li> +</ol></div> +<div class="note"><table border="0" summary="Note"> +<tr> +<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../../../../../doc/src/images/note.png"></td> +<th align="left">Note</th> +</tr> +<tr><td align="left" valign="top"><p> + <span class="bold"><strong>Note that at this time you must not call <a href="http://www.python.org/doc/current/api/initialization.html#l2h-656" target="_top">Py_Finalize</a>() + to stop the interpreter. This may be fixed in a future version of boost.python.</strong></span> + </p></td></tr> +</table></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"><strong>Now that we can embed the interpreter in + our programs, lets see how to put it to use...</strong></span></em></span> + </p></blockquote></div> +<div class="section"> +<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 <code class="literal">PyObject</code>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/c-api/refcounting.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> +<h3> +<a name="using_the_interpreter.running_python_code"></a> + Running Python code + </h3> +<p> + Boost.python provides three related functions to run Python code from C++. + </p> +<pre class="programlisting"><span class="identifier">object</span> <span class="identifier">eval</span><span class="special">(</span><span class="identifier">str</span> <span class="identifier">expression</span><span class="special">,</span> <span class="identifier">object</span> <span class="identifier">globals</span> <span class="special">=</span> <span class="identifier">object</span><span class="special">(),</span> <span class="identifier">object</span> <span class="identifier">locals</span> <span class="special">=</span> <span class="identifier">object</span><span class="special">())</span> +<span class="identifier">object</span> <span class="identifier">exec</span><span class="special">(</span><span class="identifier">str</span> <span class="identifier">code</span><span class="special">,</span> <span class="identifier">object</span> <span class="identifier">globals</span> <span class="special">=</span> <span class="identifier">object</span><span class="special">(),</span> <span class="identifier">object</span> <span class="identifier">locals</span> <span class="special">=</span> <span class="identifier">object</span><span class="special">())</span> +<span class="identifier">object</span> <span class="identifier">exec_file</span><span class="special">(</span><span class="identifier">str</span> <span class="identifier">filename</span><span class="special">,</span> <span class="identifier">object</span> <span class="identifier">globals</span> <span class="special">=</span> <span class="identifier">object</span><span class="special">(),</span> <span class="identifier">object</span> <span class="identifier">locals</span> <span class="special">=</span> <span class="identifier">object</span><span class="special">())</span> +</pre> +<p> + eval evaluates the given expression and returns the resulting value. exec + executes the given code (typically a set of statements) returning the result, + and exec_file executes the code contained in the given file. + </p> +<p> + The <code class="literal">globals</code> and <code class="literal">locals</code> 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 <code class="literal">__main__</code> module for both parameters. + </p> +<p> + Boost.python provides a function to import a module: + </p> +<pre class="programlisting"><span class="identifier">object</span> <span class="identifier">import</span><span class="special">(</span><span class="identifier">str</span> <span class="identifier">name</span><span class="special">)</span> +</pre> +<p> + import imports a python module (potentially loading it into the running process + first), and returns it. + </p> +<p> + Let's import the <code class="literal">__main__</code> module and run some Python code + in its namespace: + </p> +<pre class="programlisting"><span class="identifier">object</span> <span class="identifier">main_module</span> <span class="special">=</span> <span class="identifier">import</span><span class="special">(</span><span class="string">"__main__"</span><span class="special">);</span> +<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> + +<span class="identifier">object</span> <span class="identifier">ignored</span> <span class="special">=</span> <span class="identifier">exec</span><span class="special">(</span><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 class="special">,</span> + <span class="identifier">main_namespace</span><span class="special">);</span> +</pre> +<p> + This should create a file called 'hello.txt' in the current directory containing + a phrase that is well-known in programming circles. + </p> +<h3> +<a name="using_the_interpreter.manipulating_python_objects"></a> + Manipulating Python objects + </h3> +<p> + Often we'd like to have a 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 <code class="literal">object</code> class and its + derivatives. We've already seen that they can be constructed from a <code class="literal">handle</code>. + 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">import</span><span class="special">(</span><span class="string">"__main__"</span><span class="special">);</span> +<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> +<span class="identifier">object</span> <span class="identifier">ignored</span> <span class="special">=</span> <span class="identifier">exec</span><span class="special">(</span><span class="string">"result = 5 ** 2"</span><span class="special">,</span> <span class="identifier">main_namespace</span><span class="special">);</span> +<span class="keyword">int</span> <span class="identifier">five_squared</span> <span class="special">=</span> <span class="identifier">extract</span><span class="special"><</span><span class="keyword">int</span><span class="special">>(</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 <code class="literal">__main__</code> 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 + use eval instead, which returns the result directly: + </p> +<pre class="programlisting"><span class="identifier">object</span> <span class="identifier">result</span> <span class="special">=</span> <span class="identifier">eval</span><span class="special">(</span><span class="string">"5 ** 2"</span><span class="special">);</span> +<span class="keyword">int</span> <span class="identifier">five_squared</span> <span class="special">=</span> <span class="identifier">extract</span><span class="special"><</span><span class="keyword">int</span><span class="special">>(</span><span class="identifier">result</span><span class="special">);</span> +</pre> +<h3> +<a name="using_the_interpreter.exception_handling"></a> + Exception handling + </h3> +<p> + If an exception occurs in the evaluation of the python expression, <a href="../../../../v2/errors.html#error_already_set-spec" target="_top">error_already_set</a> + is thrown: + </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">eval</span><span class="special">(</span><span class="string">"5/0"</span><span class="special">);</span> + <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"><</span><span class="keyword">int</span><span class="special">>(</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="keyword">const</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 <code class="literal">error_already_set</code> 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="keyword">const</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> +</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"><div class="copyright-footer">Copyright © 2002-2005 Joel + de Guzman, David Abrahams<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></td> +</tr></table> +<hr> +<div class="spirit-nav"> +<a accesskey="p" href="object.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="iterators.html"><img src="../../../../../../../doc/src/images/next.png" alt="Next"></a> +</div> +</body> +</html> diff --git a/libs/python/doc/tutorial/doc/html/python/exception.html b/libs/python/doc/tutorial/doc/html/python/exception.html new file mode 100644 index 000000000..7c053a7e8 --- /dev/null +++ b/libs/python/doc/tutorial/doc/html/python/exception.html @@ -0,0 +1,63 @@ +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII"> +<title>Exception Translation</title> +<link rel="stylesheet" href="../../../../../../../doc/src/boostbook.css" type="text/css"> +<meta name="generator" content="DocBook XSL Stylesheets V1.76.1"> +<link rel="home" href="../index.html" title="Chapter 1. python 2.0"> +<link rel="up" href="../index.html" title="Chapter 1. python 2.0"> +<link rel="prev" href="iterators.html" title="Iterators"> +<link rel="next" href="techniques.html" title="General Techniques"> +</head> +<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"> +<table cellpadding="2" width="100%"><tr> +<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../../boost.png"></td> +<td align="center"><a href="../../../../../../../index.html">Home</a></td> +<td align="center"><a href="../../../../../../../libs/libraries.htm">Libraries</a></td> +<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td> +<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td> +<td align="center"><a href="../../../../../../../more/index.htm">More</a></td> +</tr></table> +<hr> +<div class="spirit-nav"> +<a accesskey="p" href="iterators.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="techniques.html"><img src="../../../../../../../doc/src/images/next.png" alt="Next"></a> +</div> +<div class="section"> +<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"><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"><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">&</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"><</span> + <span class="identifier">PodBayDoorException</span><span class="special">>(</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"><div class="copyright-footer">Copyright © 2002-2005 Joel + de Guzman, David Abrahams<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></td> +</tr></table> +<hr> +<div class="spirit-nav"> +<a accesskey="p" href="iterators.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="techniques.html"><img src="../../../../../../../doc/src/images/next.png" alt="Next"></a> +</div> +</body> +</html> diff --git a/libs/python/doc/tutorial/doc/html/python/exposing.html b/libs/python/doc/tutorial/doc/html/python/exposing.html new file mode 100644 index 000000000..5547b2f20 --- /dev/null +++ b/libs/python/doc/tutorial/doc/html/python/exposing.html @@ -0,0 +1,591 @@ +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII"> +<title>Exposing Classes</title> +<link rel="stylesheet" href="../../../../../../../doc/src/boostbook.css" type="text/css"> +<meta name="generator" content="DocBook XSL Stylesheets V1.76.1"> +<link rel="home" href="../index.html" title="Chapter 1. python 2.0"> +<link rel="up" href="../index.html" title="Chapter 1. python 2.0"> +<link rel="prev" href="hello.html" title="Building Hello World"> +<link rel="next" href="functions.html" title="Functions"> +</head> +<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"> +<table cellpadding="2" width="100%"><tr> +<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../../boost.png"></td> +<td align="center"><a href="../../../../../../../index.html">Home</a></td> +<td align="center"><a href="../../../../../../../libs/libraries.htm">Libraries</a></td> +<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td> +<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td> +<td align="center"><a href="../../../../../../../more/index.htm">More</a></td> +</tr></table> +<hr> +<div class="spirit-nav"> +<a accesskey="p" href="hello.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="functions.html"><img src="../../../../../../../doc/src/images/next.png" alt="Next"></a> +</div> +<div class="section"> +<div class="titlepage"><div><div><h2 class="title" style="clear: both"> +<a name="python.exposing"></a>Exposing Classes</h2></div></div></div> +<div class="toc"><dl> +<dt><span class="section"><a href="exposing.html#python.constructors">Constructors</a></span></dt> +<dt><span class="section"><a href="exposing.html#python.class_data_members">Class Data Members</a></span></dt> +<dt><span class="section"><a href="exposing.html#python.class_properties">Class Properties</a></span></dt> +<dt><span class="section"><a href="exposing.html#python.inheritance">Inheritance</a></span></dt> +<dt><span class="section"><a href="exposing.html#python.class_virtual_functions">Class Virtual Functions</a></span></dt> +<dt><span class="section"><a href="exposing.html#python.virtual_functions_with_default_implementations">Virtual Functions with Default Implementations</a></span></dt> +<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> +<p> + 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">-></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"><span class="preprocessor">#include</span> <span class="special"><</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">></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">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"><</span><span class="identifier">World</span><span class="special">>(</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">&</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">&</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 <code class="literal">greet</code> + and <code class="literal">set</code>. Now, after building our module as a shared library, + we may use our class <code class="literal">World</code> in Python. Here's a sample Python + session: + </p> +<pre class="programlisting"><span class="special">>>></span> <span class="keyword">import</span> <span class="identifier">hello</span> +<span class="special">>>></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">>>></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">>>></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"> +<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 <code class="literal">World</code> + 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">>>></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> +<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">-></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 <code class="literal">World</code> has no default constructor; our previous + wrapping code would fail to compile when the library tried to expose it. + We have to tell <code class="literal">class_<World></code> about the constructor + we want to expose instead. + </p> +<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special"><</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">></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">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"><</span><span class="identifier">World</span><span class="special">>(</span><span class="string">"World"</span><span class="special">,</span> <span class="identifier">init</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="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"greet"</span><span class="special">,</span> <span class="special">&</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">&</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> + <code class="literal">init<std::string>()</code> exposes the constructor taking + in a <code class="literal">std::string</code> (in Python, constructors are spelled + "<code class="literal">"__init__"</code>"). + </p> +<p> + We can expose additional constructors by passing more <code class="literal">init<...></code>s + to the <code class="literal">def()</code> 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"><</span><span class="identifier">World</span><span class="special">>(</span><span class="string">"World"</span><span class="special">,</span> <span class="identifier">init</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="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">init</span><span class="special"><</span><span class="keyword">double</span><span class="special">,</span> <span class="keyword">double</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">&</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">&</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 <code class="literal">no_init</code> instead: + </p> +<pre class="programlisting"><span class="identifier">class_</span><span class="special"><</span><span class="identifier">Abstract</span><span class="special">>(</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 <code class="literal">__init__</code> method which always raises + a Python RuntimeError exception. + </p> +</div> +<div class="section"> +<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"><strong>read-only</strong></span> + or <span class="bold"><strong>read-write</strong></span>. Consider this class <code class="literal">Var</code>: + </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++ <code class="literal">Var</code> class and its data members can be exposed + to Python: + </p> +<pre class="programlisting"><span class="identifier">class_</span><span class="special"><</span><span class="identifier">Var</span><span class="special">>(</span><span class="string">"Var"</span><span class="special">,</span> <span class="identifier">init</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="special">.</span><span class="identifier">def_readonly</span><span class="special">(</span><span class="string">"name"</span><span class="special">,</span> <span class="special">&</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">&</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> +<pre class="programlisting"><span class="special">>>></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">>>></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">>>></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 <code class="literal">name</code> is exposed as <span class="bold"><strong>read-only</strong></span> + while <code class="literal">value</code> is exposed as <span class="bold"><strong>read-write</strong></span>. + </p> +<pre class="programlisting"><span class="special">>>></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">"<stdin>"</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="error">?</span> +<span class="identifier">AttributeError</span><span class="special">:</span> <span class="identifier">can</span><span class="error">'</span><span class="identifier">t</span> <span class="identifier">set</span> <span class="identifier">attribute</span> +</pre> +</div> +<div class="section"> +<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> +<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 <code class="literal">Num</code> + class using Boost.Python: + </p> +<pre class="programlisting"><span class="identifier">class_</span><span class="special"><</span><span class="identifier">Num</span><span class="special">>(</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">&</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">&</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">Num</span><span class="special">::</span><span class="identifier">set</span><span class="special">);</span> +</pre> +<p> + And at last, in Python: + </p> +<pre class="programlisting"><span class="special">>>></span> <span class="identifier">x</span> <span class="special">=</span> <span class="identifier">Num</span><span class="special">()</span> +<span class="special">>>></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">>>></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">>>></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 <code class="literal">rovalue</code> is exposed as + <span class="bold"><strong>read-only</strong></span> since the <code class="literal">rovalue</code> + setter member function is not passed in: + </p> +<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">&</span><span class="identifier">Num</span><span class="special">::</span><span class="identifier">get</span><span class="special">)</span> +</pre> +</div> +<div class="section"> +<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> +<p> + 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 <code class="literal">Base</code> and <code class="literal">Derived</code> + 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 <code class="literal">Base</code>: + </p> +<pre class="programlisting"><span class="identifier">class_</span><span class="special"><</span><span class="identifier">Base</span><span class="special">>(</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 <code class="literal">Derived</code> + and its base class <code class="literal">Base</code>. Thus: + </p> +<pre class="programlisting"><span class="identifier">class_</span><span class="special"><</span><span class="identifier">Derived</span><span class="special">,</span> <span class="identifier">bases</span><span class="special"><</span><span class="identifier">Base</span><span class="special">></span> <span class="special">>(</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> +<div class="orderedlist"><ol class="orderedlist" type="1"> +<li class="listitem"> + Derived automatically inherits all of Base's Python methods (wrapped + C++ member functions) + </li> +<li class="listitem"> + <span class="bold"><strong>If</strong></span> Base is polymorphic, <code class="literal">Derived</code> + objects which have been passed to Python via a pointer or reference to + <code class="literal">Base</code> can be passed where a pointer or reference to + <code class="literal">Derived</code> is expected. + </li> +</ol></div> +<p> + Now, we will expose the C++ free functions <code class="literal">b</code> and <code class="literal">d</code> + and <code class="literal">factory</code>: + </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 <code class="literal">factory</code> is being used to generate + new instances of class <code class="literal">Derived</code>. In such cases, we use + <code class="literal">return_value_policy<manage_new_object></code> to instruct + Python to adopt the pointer to <code class="literal">Base</code> and hold the instance + in a new Python <code class="literal">Base</code> object until the the Python object + is destroyed. We will see more of Boost.Python <a class="link" 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"><</span><span class="identifier">manage_new_object</span><span class="special">>());</span> +</pre> +</div> +<div class="section"> +<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 will learn how to make functions behave polymorphically + through virtual functions. Continuing our example, let us add a virtual function + to our <code class="literal">Base</code> 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 <code class="computeroutput"><span class="identifier">Base</span></code>. Yet, when + you have a virtual function that's going to be overridden in Python and called + polymorphically <span class="bold"><strong>from C++</strong></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 <code class="computeroutput"><span class="identifier">Base</span></code> + 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"><</span><span class="identifier">Base</span><span class="special">></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">-></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 <code class="computeroutput"><span class="identifier">Base</span></code>, + we also multiply- inherited <code class="computeroutput"><span class="identifier">wrapper</span><span class="special"><</span><span class="identifier">Base</span><span class="special">></span></code> (See <a href="../../../../v2/wrapper.html" target="_top">Wrapper</a>). + The <code class="computeroutput"><span class="identifier">wrapper</span></code> template makes + the job of wrapping classes that are meant to overridden in Python, easier. + </p> +<div class="sidebar"> +<div class="titlepage"></div> +<p> + <span class="inlinemediaobject"><img src="../images/alert.png" alt="alert"></span> <span class="bold"><strong>MSVC6/7 Workaround</strong></span> + </p> +<p> + If you are using Microsoft Visual C++ 6 or 7, you have to write <code class="computeroutput"><span class="identifier">f</span></code> as: + </p> +<p> + <code class="computeroutput"><span class="keyword">return</span> <span class="identifier">call</span><span class="special"><</span><span class="keyword">int</span><span class="special">>(</span><span class="keyword">this</span><span class="special">-></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></code>. + </p> +</div> +<p> + BaseWrap's overridden virtual member function <code class="computeroutput"><span class="identifier">f</span></code> + in effect calls the corresponding method of the Python object through <code class="computeroutput"><span class="identifier">get_override</span></code>. + </p> +<p> + Finally, exposing <code class="computeroutput"><span class="identifier">Base</span></code>: + </p> +<pre class="programlisting"><span class="identifier">class_</span><span class="special"><</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">>(</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">(&</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> + <code class="computeroutput"><span class="identifier">pure_virtual</span></code> signals Boost.Python + that the function <code class="computeroutput"><span class="identifier">f</span></code> is a + pure virtual function. + </p> +<div class="note"><table border="0" summary="Note"> +<tr> +<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../../../../../doc/src/images/note.png"></td> +<th align="left">Note</th> +</tr> +<tr><td align="left" valign="top"> +<p> + <span class="bold"><strong>member function and methods</strong></span> + </p> +<p> + Python, like many object oriented languages uses the term <span class="bold"><strong>methods</strong></span>. + Methods correspond roughly to C++'s <span class="bold"><strong>member functions</strong></span> + </p> +</td></tr> +</table></div> +</div> +<div class="section"> +<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"><strong>non</strong></span>-pure-virtual + functions instead, the mechanism is a bit different. + </p> +<p> + Recall that in the <a class="link" 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 <code class="literal">f</code>. If, however, its member + function <code class="literal">f</code> 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"><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"><</span><span class="identifier">Base</span><span class="special">></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">-></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">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">-></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 <code class="computeroutput"><span class="identifier">BaseWrap</span><span class="special">::</span><span class="identifier">f</span></code>. Now, + we have to check if there is an override for <code class="computeroutput"><span class="identifier">f</span></code>. + If none, then we call <code class="computeroutput"><span class="identifier">Base</span><span class="special">::</span><span class="identifier">f</span><span class="special">()</span></code>. + </p> +<div class="sidebar"> +<div class="titlepage"></div> +<p> + <span class="inlinemediaobject"><img src="../images/alert.png" alt="alert"></span> <span class="bold"><strong>MSVC6/7 Workaround</strong></span> + </p> +<p> + If you are using Microsoft Visual C++ 6 or 7, you have to rewrite the line + with the <code class="computeroutput"><span class="special">*</span><span class="identifier">note</span><span class="special">*</span></code> as: + </p> +<p> + <code class="computeroutput"><span class="keyword">return</span> <span class="identifier">call</span><span class="special"><</span><span class="keyword">char</span> <span class="keyword">const</span><span class="special">*>(</span><span class="identifier">f</span><span class="special">.</span><span class="identifier">ptr</span><span class="special">());</span></code>. + </p> +</div> +<p> + Finally, exposing: + </p> +<pre class="programlisting"><span class="identifier">class_</span><span class="special"><</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">>(</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">&</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="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 <code class="computeroutput"><span class="special">&</span><span class="identifier">Base</span><span class="special">::</span><span class="identifier">f</span></code> and <code class="computeroutput"><span class="special">&</span><span class="identifier">BaseWrap</span><span class="special">::</span><span class="identifier">default_f</span></code>. Boost.Python needs to keep track + of 1) the dispatch function <code class="literal">f</code> and 2) the forwarding function + to its default implementation <code class="literal">default_f</code>. There's a special + <code class="literal">def</code> function for this purpose. + </p> +<p> + In Python, the results would be as expected: + </p> +<pre class="programlisting"><span class="special">>>></span> <span class="identifier">base</span> <span class="special">=</span> <span class="identifier">Base</span><span class="special">()</span> +<span class="special">>>></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">>>></span> <span class="identifier">derived</span> <span class="special">=</span> <span class="identifier">Derived</span><span class="special">()</span> +</pre> +<p> + Calling <code class="literal">base.f()</code>: + </p> +<pre class="programlisting"><span class="special">>>></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 <code class="literal">derived.f()</code>: + </p> +<pre class="programlisting"><span class="special">>>></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"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="python.class_operators_special_functions"></a>Class Operators/Special Functions</h3></div></div></div> +<h3> +<a name="class_operators_special_functions.python_operators"></a> + Python Operators + </h3> +<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 <code class="literal">FilePos</code> and a set of operators + that take on FilePos instances: + </p> +<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> + +<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">&</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">&</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="keyword">bool</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> +</pre> +<p> + 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"><</span><span class="identifier">FilePos</span><span class="special">>(</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"><</span><span class="keyword">int</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="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 + <code class="literal">self</code> refers to FilePos object. Also, not every class + <code class="literal">T</code> that you might need to interact with in an operator + expression is (cheaply) default-constructible. You can use <code class="literal">other<T>()</code> + in place of an actual <code class="literal">T</code> instance when writing "self + expressions". + </p> +<h3> +<a name="class_operators_special_functions.special_methods"></a> + Special Methods + </h3> +<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"><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">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">&</span> <span class="keyword">operator</span><span class="special"><<(</span><span class="identifier">ostream</span><span class="special">&,</span><span class="identifier">Rational</span><span class="special">);</span> + +<span class="identifier">class_</span><span class="special"><</span><span class="identifier">Rational</span><span class="special">>(</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"><</span><span class="identifier">Rational</span><span class="special">>))</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> +<div class="note"><table border="0" summary="Note"> +<tr> +<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../../../../../doc/src/images/note.png"></td> +<th align="left">Note</th> +</tr> +<tr><td align="left" valign="top"><p> + What is the business of <code class="computeroutput"><span class="keyword">operator</span><span class="special"><<</span></code>? Well, the method <code class="computeroutput"><span class="identifier">str</span></code> requires the <code class="computeroutput"><span class="keyword">operator</span><span class="special"><<</span></code> to do its work (i.e. <code class="computeroutput"><span class="keyword">operator</span><span class="special"><<</span></code> + is used by the method defined by <code 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></code>. + </p></td></tr> +</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"><div class="copyright-footer">Copyright © 2002-2005 Joel + de Guzman, David Abrahams<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></td> +</tr></table> +<hr> +<div class="spirit-nav"> +<a accesskey="p" href="hello.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="functions.html"><img src="../../../../../../../doc/src/images/next.png" alt="Next"></a> +</div> +</body> +</html> diff --git a/libs/python/doc/tutorial/doc/html/python/functions.html b/libs/python/doc/tutorial/doc/html/python/functions.html new file mode 100644 index 000000000..ddd5bc7b7 --- /dev/null +++ b/libs/python/doc/tutorial/doc/html/python/functions.html @@ -0,0 +1,586 @@ +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII"> +<title>Functions</title> +<link rel="stylesheet" href="../../../../../../../doc/src/boostbook.css" type="text/css"> +<meta name="generator" content="DocBook XSL Stylesheets V1.76.1"> +<link rel="home" href="../index.html" title="Chapter 1. python 2.0"> +<link rel="up" href="../index.html" title="Chapter 1. python 2.0"> +<link rel="prev" href="exposing.html" title="Exposing Classes"> +<link rel="next" href="object.html" title="Object Interface"> +</head> +<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"> +<table cellpadding="2" width="100%"><tr> +<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../../boost.png"></td> +<td align="center"><a href="../../../../../../../index.html">Home</a></td> +<td align="center"><a href="../../../../../../../libs/libraries.htm">Libraries</a></td> +<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td> +<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td> +<td align="center"><a href="../../../../../../../more/index.htm">More</a></td> +</tr></table> +<hr> +<div class="spirit-nav"> +<a accesskey="p" href="exposing.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="object.html"><img src="../../../../../../../doc/src/images/next.png" alt="Next"></a> +</div> +<div class="section"> +<div class="titlepage"><div><div><h2 class="title" style="clear: both"> +<a name="python.functions"></a>Functions</h2></div></div></div> +<div class="toc"><dl> +<dt><span class="section"><a href="functions.html#python.call_policies">Call Policies</a></span></dt> +<dt><span class="section"><a href="functions.html#python.overloading">Overloading</a></span></dt> +<dt><span class="section"><a href="functions.html#python.default_arguments">Default Arguments</a></span></dt> +<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 will see some facilities to make exposing C++ functions to Python safe from + potential pifalls such as dangling pointers and references. We will 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 + <code class="literal">>>> import this</code>. + </p> +<pre class="programlisting">>>> import this +The Zen of Python, by Tim Peters +Beautiful is better than ugly. +Explicit is better than implicit. +Simple is better than complex. +Complex is better than complicated. +Flat is better than nested. +Sparse is better than dense. +Readability counts. +Special cases aren't special enough to break the rules. +Although practicality beats purity. +Errors should never pass silently. +Unless explicitly silenced. +In the face of ambiguity, refuse the temptation to guess. +There should be one-- and preferably only one --obvious way to do it +Although that way may not be obvious at first unless you're Dutch. +Now is better than never. +Although never is often better than <span class="bold"><strong>right</strong></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! +</pre> +<div class="section"> +<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"><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">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"><span class="special">>>></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="preprocessor"># 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">>>></span> <span class="identifier">del</span> <span class="identifier">y</span> +<span class="special">>>></span> <span class="identifier">x</span><span class="special">.</span><span class="identifier">some_method</span><span class="special">()</span> <span class="preprocessor"># CRASH</span><span class="special">!</span> +</pre> +<p> + What's the problem? + </p> +<p> + Well, what if f() was implemented as shown below: + </p> +<pre class="programlisting"><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">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& 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> +<div class="orderedlist"><ol class="orderedlist" type="1"> +<li class="listitem"> + <code class="literal">f</code> is called passing in a reference to <code class="literal">y</code> + and a pointer to <code class="literal">z</code> + </li> +<li class="listitem"> + A reference to <code class="literal">y.x</code> is returned + </li> +<li class="listitem"> + <code class="literal">y</code> is deleted. <code class="literal">x</code> is a dangling reference + </li> +<li class="listitem"> + <code class="literal">x.some_method()</code> is called + </li> +<li class="listitem"> + <span class="bold"><strong>BOOM!</strong></span> + </li> +</ol></div> +<p> + We could copy result into a new object: + </p> +<pre class="programlisting"><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">set</span><span class="special">(</span><span class="number">42</span><span class="special">)</span> <span class="comment"># Result disappears</span> +<span class="special">>>></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> +<p> + Our problems do not end there. Suppose Y is implemented as follows: + </p> +<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">-></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 <code class="literal">z</code> 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">>>></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="preprocessor"># y</span> <span class="identifier">refers</span> <span class="identifier">to</span> <span class="identifier">z</span> +<span class="special">>>></span> <span class="identifier">del</span> <span class="identifier">z</span> <span class="preprocessor"># Kill</span> <span class="identifier">the</span> <span class="identifier">z</span> <span class="identifier">object</span> +<span class="special">>>></span> <span class="identifier">y</span><span class="special">.</span><span class="identifier">z_value</span><span class="special">()</span> <span class="preprocessor"># CRASH</span><span class="special">!</span> +</pre> +<p> + For reference, here's the implementation of <code class="literal">f</code> again: + </p> +<pre class="programlisting"><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">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> +<div class="orderedlist"><ol class="orderedlist" type="1"> +<li class="listitem"> + <code class="literal">f</code> is called passing in a reference to <code class="literal">y</code> + and a pointer to <code class="literal">z</code> + </li> +<li class="listitem"> + A pointer to <code class="literal">z</code> is held by <code class="literal">y</code> + </li> +<li class="listitem"> + A reference to <code class="literal">y.x</code> is returned + </li> +<li class="listitem"> + <code class="literal">z</code> is deleted. <code class="literal">y.z</code> is a dangling + pointer + </li> +<li class="listitem"> + <code class="literal">y.z_value()</code> is called + </li> +<li class="listitem"> + <code class="literal">z->value()</code> is called + </li> +<li class="listitem"> + <span class="bold"><strong>BOOM!</strong></span> + </li> +</ol></div> +<h3> +<a name="call_policies.call_policies"></a> + Call Policies + </h3> +<p> + Call Policies may be used in situations such as the example detailed above. + In our example, <code class="literal">return_internal_reference</code> and <code class="literal">with_custodian_and_ward</code> + 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"><</span><span class="number">1</span><span class="special">,</span> + <span class="identifier">with_custodian_and_ward</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="special">>());</span> +</pre> +<p> + What are the <code class="literal">1</code> and <code class="literal">2</code> parameters, you + ask? + </p> +<pre class="programlisting"><span class="identifier">return_internal_reference</span><span class="special"><</span><span class="number">1</span> +</pre> +<p> + Informs Boost.Python that the first argument, in our case <code class="literal">Y& + y</code>, is the owner of the returned reference: <code class="literal">X&</code>. + The "<code class="literal">1</code>" simply specifies the first argument. + In short: "return an internal reference <code class="literal">X&</code> owned + by the 1st argument <code class="literal">Y& y</code>". + </p> +<pre class="programlisting"><span class="identifier">with_custodian_and_ward</span><span class="special"><</span><span class="number">1</span><span class="special">,</span> <span class="number">2</span><span class="special">></span> +</pre> +<p> + Informs Boost.Python that the lifetime of the argument indicated by ward + (i.e. the 2nd argument: <code class="literal">Z* z</code>) is dependent on the lifetime + of the argument indicated by custodian (i.e. the 1st argument: <code class="literal">Y& + y</code>). + </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"><span class="identifier">policy1</span><span class="special"><</span><span class="identifier">args</span><span class="special">...,</span> + <span class="identifier">policy2</span><span class="special"><</span><span class="identifier">args</span><span class="special">...,</span> + <span class="identifier">policy3</span><span class="special"><</span><span class="identifier">args</span><span class="special">...></span> <span class="special">></span> <span class="special">></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> +<div class="itemizedlist"><ul class="itemizedlist" type="disc"> +<li class="listitem"> + <span class="bold"><strong>with_custodian_and_ward</strong></span>: Ties lifetimes + of the arguments + </li> +<li class="listitem"> + <span class="bold"><strong>with_custodian_and_ward_postcall</strong></span>: Ties + lifetimes of the arguments and results + </li> +<li class="listitem"> + <span class="bold"><strong>return_internal_reference</strong></span>: Ties lifetime + of one argument to that of result + </li> +<li class="listitem"> + <span class="bold"><strong>return_value_policy<T> with T one of:</strong></span> + <div class="itemizedlist"><ul class="itemizedlist" type="circle"> +<li class="listitem"> + <span class="bold"><strong>reference_existing_object</strong></span>: naive + (dangerous) approach + </li> +<li class="listitem"> + <span class="bold"><strong>copy_const_reference</strong></span>: Boost.Python + v1 approach + </li> +<li class="listitem"> + <span class="bold"><strong>copy_non_const_reference</strong></span>: + </li> +<li class="listitem"> + <span class="bold"><strong>manage_new_object</strong></span>: Adopt a pointer + and hold the instance + </li> +</ul></div> + </li> +</ul></div> +<div class="sidebar"> +<div class="titlepage"></div> +<p> + <span class="inlinemediaobject"><img src="../images/smiley.png" alt="smiley"></span> <span class="bold"><strong>Remember the Zen, Luke:</strong></span> + </p> +<p> + "Explicit is better than implicit" + </p> +<p> + "In the face of ambiguity, refuse the temptation to guess" + </p> +</div> +</div> +<div class="section"> +<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> +<p> + 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> + + <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> + + <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> + + <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 will 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">&</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">&</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">&</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">&</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"><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"> +<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 <code class="literal">f</code> + 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 <code class="literal">f</code> 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 <code class="literal">def</code> 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 class="link" 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="keyword">return</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="keyword">return</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> + + <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> +<div class="itemizedlist"><ul class="itemizedlist" type="disc"> +<li class="listitem"> + have default arguments, or + </li> +<li class="listitem"> + are overloaded with a common sequence of initial arguments + </li> +</ul></div> +<h3> +<a name="default_arguments.boost_python_function_overloads"></a> + BOOST_PYTHON_FUNCTION_OVERLOADS + </h3> +<p> + 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"><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 <code class="literal">foo_overloads</code> that can be passed on to <code class="literal">def(...)</code>. + The third and fourth macro argument are the minimum arguments and maximum + arguments, respectively. In our <code class="literal">foo</code> function the minimum + number of arguments is 1 and the maximum number of arguments is 4. The <code class="literal">def(...)</code> + 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> +<h3> +<a name="default_arguments.boost_python_member_function_overloads"></a> + BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS + </h3> +<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 <code class="literal">BOOST_PYTHON_FUNCTION_OVERLOADS</code>, <code class="literal">BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</code> + 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"><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 <code class="literal">wack_em</code> + 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 <code class="literal">george_overloads</code> that can then be used + as an argument to <code class="literal">def(...)</code>: + </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">&</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> +<h3> +<a name="default_arguments.init_and_optional"></a> + init and optional + </h3> +<p> + A similar facility is provided for class constructors, again, with default + arguments or a sequence of overloads. Remember <code class="literal">init<...></code>? + 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"><span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">init</span><span class="special"><</span><span class="keyword">int</span><span class="special">,</span> <span class="identifier">optional</span><span class="special"><</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">></span> <span class="special">>())</span> +</pre> +<p> + Notice the use of <code class="literal">init<...></code> and <code class="literal">optional<...></code> + to signify the default (optional arguments). + </p> +</div> +<div class="section"> +<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 <code class="literal">BOOST_PYTHON_FUNCTION_OVERLOADS</code> + and <code class="literal">BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</code> 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> + +<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> + +<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> + +<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"><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"><span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"foo"</span><span class="special">,</span> <span class="special">(</span><span class="keyword">void</span><span class="special">(*)(</span><span class="keyword">bool</span><span class="special">,</span> <span class="keyword">int</span><span class="special">,</span> <span class="keyword">char</span><span class="special">))</span><span class="number">0</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> +<h3> +<a name="auto_overloading.manual_wrapping"></a> + Manual Wrapping + </h3> +<p> + It is important to emphasize however that <span class="bold"><strong>the overloaded + functions must have a common sequence of initial arguments</strong></span>. Otherwise, + our scheme above will not work. If this is not the case, we have to wrap + our functions <a class="link" 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 <code class="literal">BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</code> + and its sister, <code class="literal">BOOST_PYTHON_FUNCTION_OVERLOADS</code>. Following + up on our example presented in the section <a class="link" 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 <code class="literal">BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</code> + to automatically wrap the first three of the <code class="literal">def</code>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"><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">&</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">&</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"><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"><div class="copyright-footer">Copyright © 2002-2005 Joel + de Guzman, David Abrahams<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></td> +</tr></table> +<hr> +<div class="spirit-nav"> +<a accesskey="p" href="exposing.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="object.html"><img src="../../../../../../../doc/src/images/next.png" alt="Next"></a> +</div> +</body> +</html> diff --git a/libs/python/doc/tutorial/doc/html/python/hello.html b/libs/python/doc/tutorial/doc/html/python/hello.html new file mode 100644 index 000000000..b78573826 --- /dev/null +++ b/libs/python/doc/tutorial/doc/html/python/hello.html @@ -0,0 +1,195 @@ +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII"> +<title>Building Hello World</title> +<link rel="stylesheet" href="../../../../../../../doc/src/boostbook.css" type="text/css"> +<meta name="generator" content="DocBook XSL Stylesheets V1.76.1"> +<link rel="home" href="../index.html" title="Chapter 1. python 2.0"> +<link rel="up" href="../index.html" title="Chapter 1. python 2.0"> +<link rel="prev" href="../index.html" title="Chapter 1. python 2.0"> +<link rel="next" href="exposing.html" title="Exposing Classes"> +</head> +<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"> +<table cellpadding="2" width="100%"><tr> +<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../../boost.png"></td> +<td align="center"><a href="../../../../../../../index.html">Home</a></td> +<td align="center"><a href="../../../../../../../libs/libraries.htm">Libraries</a></td> +<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td> +<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td> +<td align="center"><a href="../../../../../../../more/index.htm">More</a></td> +</tr></table> +<hr> +<div class="spirit-nav"> +<a accesskey="p" href="../index.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="exposing.html"><img src="../../../../../../../doc/src/images/next.png" alt="Next"></a> +</div> +<div class="section"> +<div class="titlepage"><div><div><h2 class="title" style="clear: both"> +<a name="python.hello"></a>Building Hello World</h2></div></div></div> +<h3> +<a name="hello.from_start_to_finish"></a> + From Start To Finish + </h3> +<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 will outline the steps necessary + to achieve that. We will use the build tool that comes bundled with every boost + distribution: <span class="bold"><strong>bjam</strong></span>. + </p> +<div class="note"><table border="0" summary="Note"> +<tr> +<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../../../../../doc/src/images/note.png"></td> +<th align="left">Note</th> +</tr> +<tr><td align="left" valign="top"> +<p> + <span class="bold"><strong>Building without bjam</strong></span> + </p> +<p> + 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 <code class="literal">bjam</code>. + </p> +<p> + 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. + </p> +</td></tr> +</table></div> +<p> + We will 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 the DLLs + and run a python program using the extension. + </p> +<p> + The tutorial example can be found in the directory: <code class="literal">libs/python/example/tutorial</code>. + There, you can find: + </p> +<div class="itemizedlist"><ul class="itemizedlist" type="disc"> +<li class="listitem"> + hello.cpp + </li> +<li class="listitem"> + hello.py + </li> +<li class="listitem"> + Jamroot + </li> +</ul></div> +<p> + The <code class="literal">hello.cpp</code> file is our C++ hello world example. The + <code class="literal">Jamroot</code> is a minimalist <span class="emphasis"><em>bjam</em></span> script + that builds the DLLs for us. Finally, <code class="literal">hello.py</code> is our Python + program that uses the extension in <code class="literal">hello.cpp</code>. + </p> +<p> + Before anything else, you should have the bjam executable in your boost directory + or somewhere in your path such that <code class="literal">bjam</code> 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> +<h3> +<a name="hello.let_s_jam_"></a> + Let's Jam! + </h3> +<p> + <span class="inlinemediaobject"><img src="../images/jam.png" alt="jam"></span> + </p> +<p> + <a href="../../../../../example/tutorial/Jamroot" target="_top">Here</a> is our minimalist + Jamroot file. Simply copy the file and tweak <code class="literal">use-project boost</code> + to where your boost root directory is and your OK. + </p> +<p> + The comments contained in the Jamrules file above should be sufficient to get + you going. + </p> +<h3> +<a name="hello.running_bjam"></a> + Running bjam + </h3> +<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> + A file called user-config.jam in your home directory is used to configure your + tools. In Windows, your home directory can be found by typing: + </p> +<pre class="programlisting">ECHO %HOMEDRIVE%%HOMEPATH% +</pre> +<p> + into a command prompt window. Your file should at least have the rules for + your compiler and your python installation. A specific example of this on Windows + would be: + </p> +<pre class="programlisting"># MSVC configuration +using msvc : 8.0 ; + +# Python configuration +using python : 2.4 : C:<span class="emphasis"><em>dev/tools/Python</em></span> ; +</pre> +<p> + The first rule tells Bjam to use the MSVC 8.0 compiler and associated tools. + The second rule provides information on Python, its version and where it is + located. The above assumes that the Python installation is in <code class="literal">C:<span class="emphasis"><em>dev/tools\/Python</em></span></code>. + If you have one fairly "standard" python installation for your platform, + you might not need to do this. + </p> +<p> + Now we are ready... Be sure to <code class="literal">cd</code> to <code class="literal">libs/python/example/tutorial</code> + where the tutorial <code class="literal">"hello.cpp"</code> and the <code class="literal">"Jamroot"</code> + is situated. + </p> +<p> + Finally: + </p> +<pre class="programlisting"><span class="identifier">bjam</span> +</pre> +<p> + It should be building now: + </p> +<pre class="programlisting">cd C:\dev\boost\libs\python\example\tutorial +bjam +...patience... +...found 1101 targets... +...updating 35 targets... +</pre> +<p> + And so on... Finally: + </p> +<pre class="programlisting">Creating library <span class="emphasis"><em>path-to-boost_python.dll</em></span> + Creating library /path-to-hello_ext.exp/ +**passed** ... hello.test +...updated 35 targets... +</pre> +<p> + Or something similar. If all is well, you should now have built the DLLs and + run the Python program. + </p> +<div class="blockquote"><blockquote class="blockquote"><p> + <span class="bold"><strong>There you go... Have fun!</strong></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"><div class="copyright-footer">Copyright © 2002-2005 Joel + de Guzman, David Abrahams<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></td> +</tr></table> +<hr> +<div class="spirit-nav"> +<a accesskey="p" href="../index.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="exposing.html"><img src="../../../../../../../doc/src/images/next.png" alt="Next"></a> +</div> +</body> +</html> diff --git a/libs/python/doc/tutorial/doc/html/python/iterators.html b/libs/python/doc/tutorial/doc/html/python/iterators.html new file mode 100644 index 000000000..9fb402b6b --- /dev/null +++ b/libs/python/doc/tutorial/doc/html/python/iterators.html @@ -0,0 +1,187 @@ +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII"> +<title>Iterators</title> +<link rel="stylesheet" href="../../../../../../../doc/src/boostbook.css" type="text/css"> +<meta name="generator" content="DocBook XSL Stylesheets V1.76.1"> +<link rel="home" href="../index.html" title="Chapter 1. python 2.0"> +<link rel="up" href="../index.html" title="Chapter 1. python 2.0"> +<link rel="prev" href="embedding.html" title="Embedding"> +<link rel="next" href="exception.html" title="Exception Translation"> +</head> +<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"> +<table cellpadding="2" width="100%"><tr> +<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../../boost.png"></td> +<td align="center"><a href="../../../../../../../index.html">Home</a></td> +<td align="center"><a href="../../../../../../../libs/libraries.htm">Libraries</a></td> +<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td> +<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td> +<td align="center"><a href="../../../../../../../more/index.htm">More</a></td> +</tr></table> +<hr> +<div class="spirit-nav"> +<a accesskey="p" href="embedding.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="exception.html"><img src="../../../../../../../doc/src/images/next.png" alt="Next"></a> +</div> +<div class="section"> +<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> +<p> + <span class="bold"><strong>C++ iterators:</strong></span> + </p> +<div class="itemizedlist"><ul class="itemizedlist" type="disc"> +<li class="listitem"> + C++ has 5 type categories (random-access, bidirectional, forward, input, + output) + </li> +<li class="listitem"> + There are 2 Operation categories: reposition, access + </li> +<li class="listitem"> + A pair of iterators is needed to represent a (first/last) range. + </li> +</ul></div> +<p> + <span class="bold"><strong>Python Iterators:</strong></span> + </p> +<div class="itemizedlist"><ul class="itemizedlist" type="disc"> +<li class="listitem"> + 1 category (forward) + </li> +<li class="listitem"> + 1 operation category (next()) + </li> +<li class="listitem"> + Raises StopIteration exception at end + </li> +</ul></div> +<p> + The typical Python iteration protocol: <code class="literal"><span class="bold"><strong>for y + in x...</strong></span></code> is as follows: + </p> +<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 <code class="computeroutput"><span class="identifier">__iter__</span></code> function from C++ iterators that + is compatible with the Python iteration protocol. For example: + </p> +<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"><</span><span class="identifier">vector</span><span class="special"><</span><span class="keyword">int</span><span class="special">></span> <span class="special">>();</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_<>: + </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"><</span><span class="identifier">vector</span><span class="special"><</span><span class="keyword">int</span><span class="special">></span> <span class="special">>())</span> +</pre> +<p> + <span class="bold"><strong>range</strong></span> + </p> +<p> + We can create a Python savvy iterator using the range function: + </p> +<div class="itemizedlist"><ul class="itemizedlist" type="disc"> +<li class="listitem"> + range(start, finish) + </li> +<li class="listitem"> + range<Policies,Target>(start, finish) + </li> +</ul></div> +<p> + Here, start/finish may be one of: + </p> +<div class="itemizedlist"><ul class="itemizedlist" type="disc"> +<li class="listitem"> + member data pointers + </li> +<li class="listitem"> + member function pointers + </li> +<li class="listitem"> + adaptable function object (use Target parameter) + </li> +</ul></div> +<p> + <span class="bold"><strong>iterator</strong></span> + </p> +<div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"> + iterator<T, Policies>() + </li></ul></div> +<p> + Given a container <code class="literal">T</code>, iterator is a shortcut that simply + calls <code class="literal">range</code> with &T::begin, &T::end. + </p> +<p> + Let's put this into action... Here's an example from some hypothetical bogon + Particle accelerator code: + </p> +<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> +<pre class="programlisting"><span class="identifier">class_</span><span class="special"><</span><span class="identifier">F</span><span class="special">>(</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">(&</span><span class="identifier">F</span><span class="special">::</span><span class="identifier">p_begin</span><span class="special">,</span> <span class="special">&</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">(&</span><span class="identifier">F</span><span class="special">::</span><span class="identifier">b_begin</span><span class="special">,</span> <span class="special">&</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"><strong>stl_input_iterator</strong></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 <code class="computeroutput"><span class="identifier">stl_input_iterator</span><span class="special"><></span></code>. + Consider how we might implement a function that exposes <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">list</span><span class="special"><</span><span class="keyword">int</span><span class="special">>::</span><span class="identifier">assign</span><span class="special">()</span></code> to Python: + </p> +<pre class="programlisting"><span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">></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"><</span><span class="identifier">T</span><span class="special">>&</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"><</span><span class="identifier">T</span><span class="special">></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<int></span> +<span class="identifier">class_</span><span class="special"><</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">list</span><span class="special"><</span><span class="keyword">int</span><span class="special">></span> <span class="special">>(</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">&</span><span class="identifier">list_assign</span><span class="special"><</span><span class="keyword">int</span><span class="special">>)</span> + <span class="comment">// ...</span> + <span class="special">;</span> +</pre> +<p> + Now in Python, we can assign any integer sequence to <code class="computeroutput"><span class="identifier">list_int</span></code> + objects: + </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"><div class="copyright-footer">Copyright © 2002-2005 Joel + de Guzman, David Abrahams<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></td> +</tr></table> +<hr> +<div class="spirit-nav"> +<a accesskey="p" href="embedding.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="exception.html"><img src="../../../../../../../doc/src/images/next.png" alt="Next"></a> +</div> +</body> +</html> diff --git a/libs/python/doc/tutorial/doc/html/python/object.html b/libs/python/doc/tutorial/doc/html/python/object.html new file mode 100644 index 000000000..7bc2aa255 --- /dev/null +++ b/libs/python/doc/tutorial/doc/html/python/object.html @@ -0,0 +1,360 @@ +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII"> +<title>Object Interface</title> +<link rel="stylesheet" href="../../../../../../../doc/src/boostbook.css" type="text/css"> +<meta name="generator" content="DocBook XSL Stylesheets V1.76.1"> +<link rel="home" href="../index.html" title="Chapter 1. python 2.0"> +<link rel="up" href="../index.html" title="Chapter 1. python 2.0"> +<link rel="prev" href="functions.html" title="Functions"> +<link rel="next" href="embedding.html" title="Embedding"> +</head> +<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"> +<table cellpadding="2" width="100%"><tr> +<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../../boost.png"></td> +<td align="center"><a href="../../../../../../../index.html">Home</a></td> +<td align="center"><a href="../../../../../../../libs/libraries.htm">Libraries</a></td> +<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td> +<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td> +<td align="center"><a href="../../../../../../../more/index.htm">More</a></td> +</tr></table> +<hr> +<div class="spirit-nav"> +<a accesskey="p" href="functions.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="embedding.html"><img src="../../../../../../../doc/src/images/next.png" alt="Next"></a> +</div> +<div class="section"> +<div class="titlepage"><div><div><h2 class="title" style="clear: both"> +<a name="python.object"></a>Object Interface</h2></div></div></div> +<div class="toc"><dl> +<dt><span class="section"><a href="object.html#python.basic_interface">Basic Interface</a></span></dt> +<dt><span class="section"><a href="object.html#python.derived_object_types">Derived Object types</a></span></dt> +<dt><span class="section"><a href="object.html#python.extracting_c___objects">Extracting C++ objects</a></span></dt> +<dt><span class="section"><a href="object.html#python.enums">Enums</a></span></dt> +<dt><span class="section"><a href="object.html#python.creating_python_object">Creating <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">python</span><span class="special">::</span><span class="identifier">object</span></code> from <code class="computeroutput"><span class="identifier">PyObject</span><span class="special">*</span></code></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 <code class="literal">object</code>. We will 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++ <code class="literal">object</code>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" alt="python"></span> + </p> +<div class="section"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="python.basic_interface"></a>Basic Interface</h3></div></div></div> +<p> + Class <code class="literal">object</code> wraps <code class="literal">PyObject*</code>. All the + intricacies of dealing with <code class="literal">PyObject</code>s such as managing + reference counting are handled by the <code class="literal">object</code> class. C++ + object interoperability is seamless. Boost.Python C++ <code class="literal">object</code>s + can in fact be explicitly constructed from any C++ object. + </p> +<p> + To illustrate, this Python code snippet: + </p> +<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> + +<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> +<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> +</div> +<div class="section"> +<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 <code class="literal">object</code> types + corresponding to that of Python's: + </p> +<div class="itemizedlist"><ul class="itemizedlist" type="disc"> +<li class="listitem"> + list + </li> +<li class="listitem"> + dict + </li> +<li class="listitem"> + tuple + </li> +<li class="listitem"> + str + </li> +<li class="listitem"> + long_ + </li> +<li class="listitem"> + enum + </li> +</ul></div> +<p> + These derived <code class="literal">object</code> 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">==></span> <span class="string">"1"</span> +</pre> +<p> + Wherever appropriate, a particular derived <code class="literal">object</code> has + corresponding Python type's methods. For instance, <code class="literal">dict</code> + has a <code class="literal">keys()</code> 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> + <code class="literal">make_tuple</code> 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 <code class="literal">object</code>s are used as arguments + to functions, subtype matching is required. For example, when a function + <code class="literal">f</code>, as declared below, is wrapped, it will only accept + instances of Python's <code class="literal">str</code> 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"><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"><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 <code class="literal">"format" + % x,y,z</code> in Python, which is useful since there's no easy way to + do that in std C++. + </p> +<div class="sidebar"> +<div class="titlepage"></div> +<p> + <span class="inlinemediaobject"><img src="../images/alert.png" alt="alert"></span> <span class="bold"><strong>Beware</strong></span> the common pitfall + of forgetting that the constructors of most of Python's mutable types make + copies, just as in Python. + </p> +</div> +<p> + Python: + </p> +<pre class="programlisting"><span class="special">>>></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">>>></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"><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> +<h3> +<a name="derived_object_types.class__lt_t_gt__as_objects"></a> + class_<T> as objects + </h3> +<p> + Due to the dynamic nature of Boost.Python objects, any <code class="literal">class_<T></code> + 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"><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"><</span><span class="identifier">Vec2</span><span class="special">>(</span><span class="string">"Vec2"</span><span class="special">,</span> <span class="identifier">init</span><span class="special"><</span><span class="keyword">double</span><span class="special">,</span> <span class="keyword">double</span><span class="special">>())</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">&</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">&</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">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"> +<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 <code class="literal">extract<T></code> 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 <code class="literal">object</code> + can't be implicitly converted to <code class="literal">double</code>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"><</span><span class="keyword">double</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="identifier">Vec2</span><span class="special">&</span> <span class="identifier">v</span> <span class="special">=</span> <span class="identifier">extract</span><span class="special"><</span><span class="identifier">Vec2</span><span class="special">&>(</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 <code class="literal">object</code>. The second line attempts to <span class="emphasis"><em>extract</em></span> + the <code class="literal">Vec2</code> object from held by the Boost.Python <code class="literal">object</code>. + </p> +<p> + Take note that we said "attempt to" above. What if the Boost.Python + <code class="literal">object</code> does not really hold a <code class="literal">Vec2</code> + type? This is certainly a possibility considering the dynamic nature of Python + <code class="literal">object</code>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"><</span><span class="identifier">Vec2</span><span class="special">&></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">&</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" alt="tip"></span> The astute reader might have noticed that the <code class="literal">extract<T></code> + 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"><</span><span class="identifier">dict</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="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"> +<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 <code class="literal">enum</code> type, we'll often want to expose our C++ enums + to Python as an <code class="literal">int</code>. 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"><span class="identifier">enum_</span><span class="special"><</span><span class="identifier">choice</span><span class="special">>(</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 + <code class="literal">scope()</code>, which is usually the current module. The snippet + above creates a Python class derived from Python's <code class="literal">int</code> + type which is associated with the C++ type passed as its first parameter. + </p> +<div class="note"><table border="0" summary="Note"> +<tr> +<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../../../../../doc/src/images/note.png"></td> +<th align="left">Note</th> +</tr> +<tr><td align="left" valign="top"> +<p> + <span class="bold"><strong>what is a scope?</strong></span> + </p> +<p> + 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>. + </p> +</td></tr> +</table></div> +<p> + You can access those values in Python as + </p> +<pre class="programlisting"><span class="special">>>></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> +<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"><</span><span class="identifier">X</span><span class="special">>(</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">// Expose X::nested as X.nested</span> +<span class="identifier">enum_</span><span class="special"><</span><span class="identifier">X</span><span class="special">::</span><span class="identifier">nested</span><span class="special">>(</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 class="section"> +<div class="titlepage"><div><div><h3 class="title"> +<a name="python.creating_python_object"></a>Creating <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">python</span><span class="special">::</span><span class="identifier">object</span></code> from <code class="computeroutput"><span class="identifier">PyObject</span><span class="special">*</span></code> +</h3></div></div></div> +<p> + When you want a <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">python</span><span class="special">::</span><span class="identifier">object</span></code> to manage a pointer to <code class="computeroutput"><span class="identifier">PyObject</span><span class="special">*</span></code> + pyobj one does: + </p> +<pre class="programlisting"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">python</span><span class="special">::</span><span class="identifier">object</span> <span class="identifier">o</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">python</span><span class="special">::</span><span class="identifier">handle</span><span class="special"><>(</span><span class="identifier">pyobj</span><span class="special">));</span> +</pre> +<p> + In this case, the <code class="computeroutput"><span class="identifier">o</span></code> object, + manages the <code class="computeroutput"><span class="identifier">pyobj</span></code>, it won’t + increase the reference count on construction. + </p> +<p> + Otherwise, to use a borrowed reference: + </p> +<pre class="programlisting"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">python</span><span class="special">::</span><span class="identifier">object</span> <span class="identifier">o</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">python</span><span class="special">::</span><span class="identifier">handle</span><span class="special"><>(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">python</span><span class="special">::</span><span class="identifier">borrowed</span><span class="special">(</span><span class="identifier">pyobj</span><span class="special">)));</span> +</pre> +<p> + In this case, <code class="computeroutput"><span class="identifier">Py_INCREF</span></code> is + called, so <code class="computeroutput"><span class="identifier">pyobj</span></code> is not destructed + when object o goes out of scope. + </p> +</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"><div class="copyright-footer">Copyright © 2002-2005 Joel + de Guzman, David Abrahams<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></td> +</tr></table> +<hr> +<div class="spirit-nav"> +<a accesskey="p" href="functions.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="embedding.html"><img src="../../../../../../../doc/src/images/next.png" alt="Next"></a> +</div> +</body> +</html> diff --git a/libs/python/doc/tutorial/doc/html/python/techniques.html b/libs/python/doc/tutorial/doc/html/python/techniques.html new file mode 100644 index 000000000..34cfc4442 --- /dev/null +++ b/libs/python/doc/tutorial/doc/html/python/techniques.html @@ -0,0 +1,440 @@ +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII"> +<title>General Techniques</title> +<link rel="stylesheet" href="../../../../../../../doc/src/boostbook.css" type="text/css"> +<meta name="generator" content="DocBook XSL Stylesheets V1.76.1"> +<link rel="home" href="../index.html" title="Chapter 1. python 2.0"> +<link rel="up" href="../index.html" title="Chapter 1. python 2.0"> +<link rel="prev" href="exception.html" title="Exception Translation"> +</head> +<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"> +<table cellpadding="2" width="100%"><tr> +<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../../boost.png"></td> +<td align="center"><a href="../../../../../../../index.html">Home</a></td> +<td align="center"><a href="../../../../../../../libs/libraries.htm">Libraries</a></td> +<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td> +<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td> +<td align="center"><a href="../../../../../../../more/index.htm">More</a></td> +</tr></table> +<hr> +<div class="spirit-nav"> +<a accesskey="p" href="exception.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a> +</div> +<div class="section"> +<div class="titlepage"><div><div><h2 class="title" style="clear: both"> +<a name="python.techniques"></a>General Techniques</h2></div></div></div> +<div class="toc"><dl> +<dt><span class="section"><a href="techniques.html#python.creating_packages">Creating Packages</a></span></dt> +<dt><span class="section"><a href="techniques.html#python.extending_wrapped_objects_in_python">Extending Wrapped Objects in Python</a></span></dt> +<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> +<div class="section"> +<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> +<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) + <code class="literal">sounds</code>. 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"><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"><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> + +<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> + +<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: <code class="literal">core.pyd</code>, + <code class="literal">io.pyd</code> and <code class="literal">filters.pyd</code>. + </p> +<div class="note"><table border="0" summary="Note"> +<tr> +<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../../../../../doc/src/images/note.png"></td> +<th align="left">Note</th> +</tr> +<tr><td align="left" valign="top"><p> + The extension <code class="literal">.pyd</code> is used for python extension modules, + which are just shared libraries. Using the default for your system, like + <code class="literal">.so</code> for Unix and <code class="literal">.dll</code> for Windows, + works just as well. + </p></td></tr> +</table></div> +<p> + Now, we create this directory structure for our Python package: + </p> +<pre class="programlisting">sounds/ + __init__.py + core.pyd + filters.pyd + io.pyd +</pre> +<p> + The file <code class="literal">__init__.py</code> is what tells Python that the directory + <code class="literal">sounds/</code> 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 <code class="literal">sounds</code> + into his <a href="http://www.python.org/doc/current/tut/node8.html#SECTION008110000000000000000" target="_top">PYTHONPATH</a> + and fire up the interpreter: + </p> +<pre class="programlisting"><span class="special">>>></span> <span class="keyword">import</span> <span class="identifier">sounds</span><span class="special">.</span><span class="identifier">io</span> +<span class="special">>>></span> <span class="keyword">import</span> <span class="identifier">sounds</span><span class="special">.</span><span class="identifier">filters</span> +<span class="special">>>></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">>>></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> +<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> +<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 <code class="literal">_core.pyd</code> 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 + <span class="underline">core.pyd + filters/ + \</span>_init__.py + <span class="underline">filters.pyd + io/ + \</span>_init__.py + _io.pyd +</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> +<pre class="programlisting"><span class="special">>>></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">>>></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 <code class="literal">__init__.py</code> + magic: everything that is brought to the <code class="literal">__init__.py</code> namespace + can be accessed directly by the user. So, all we have to do is bring the + entire namespace from <code class="literal">_core.pyd</code> to <code class="literal">core/__init__.py</code>. + So add this line of code to <code class="literal">sounds/core/__init__.py</code>: + </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"><span class="special">>>></span> <span class="keyword">import</span> <span class="identifier">sounds</span><span class="special">.</span><span class="identifier">filters</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> +</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, <code class="literal">echo_noise</code>, to the <code class="literal">filters</code> + package. This function applies both the <code class="literal">echo</code> and <code class="literal">noise</code> + filters in sequence in the given <code class="literal">sound</code> object. We create + a file named <code class="literal">sounds/filters/echo_noise.py</code> 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 <code class="literal">sounds/filters/__init__.py</code>: + </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 <code class="literal">filters</code> package: + </p> +<pre class="programlisting"><span class="special">>>></span> <span class="keyword">import</span> <span class="identifier">sounds</span><span class="special">.</span><span class="identifier">filters</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_noise</span><span class="special">(...)</span> +</pre> +</div> +<div class="section"> +<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"><span class="special">>>></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">>>></span> +<span class="special">>>></span> <span class="comment"># a regular function</span> +<span class="special">>>></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">>>></span> +<span class="special">>>></span> <span class="comment"># now we turn it in a member function</span> +<span class="special">>>></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">>>></span> +<span class="special">>>></span> <span class="identifier">c</span> <span class="special">=</span> <span class="identifier">C</span><span class="special">()</span> +<span class="special">>>></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">>>></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" alt="smiley"></span> + </p> +<p> + We can do the same with classes that were wrapped with Boost.Python. Suppose + we have a class <code class="literal">point</code> in C++: + </p> +<pre class="programlisting"><span class="keyword">class</span> <span class="identifier">point</span> <span class="special">{...};</span> + +<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"><</span><span class="identifier">point</span><span class="special">>(</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 class="link" href="techniques.html#python.creating_packages" title="Creating Packages">Creating + Packages</a>, we can code directly into <code class="literal">geom/__init__.py</code>: + </p> +<pre class="programlisting"><span class="keyword">from</span> <span class="identifier">_geom</span> <span class="keyword">import</span> <span class="special">*</span> + +<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> + +<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"><strong>All</strong></span> point instances created from C++ will + also have this member function! This technique has several advantages: + </p> +<div class="itemizedlist"><ul class="itemizedlist" type="disc"> +<li class="listitem"> + Cut down compile times to zero for these additional functions + </li> +<li class="listitem"> + Reduce the memory footprint to virtually zero + </li> +<li class="listitem"> + Minimize the need to recompile + </li> +<li class="listitem"> + 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"><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> + +<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> + +<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"><span class="special">>>></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">>>></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"><span class="identifier">_point</span> <span class="special">=</span> <span class="identifier">point</span> + +<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> +</div> +<div class="section"> +<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> +<pre class="programlisting"><span class="comment">/* file point.cpp */</span> +<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">point</span><span class="special">.</span><span class="identifier">h</span><span class="special">></span> +<span class="preprocessor">#include</span> <span class="special"><</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">></span> + +<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"><</span><span class="identifier">point</span><span class="special">>(</span><span class="string">"point"</span><span class="special">)...;</span> +<span class="special">}</span> + +<span class="comment">/* file triangle.cpp */</span> +<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">triangle</span><span class="special">.</span><span class="identifier">h</span><span class="special">></span> +<span class="preprocessor">#include</span> <span class="special"><</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">></span> + +<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"><</span><span class="identifier">triangle</span><span class="special">>(</span><span class="string">"triangle"</span><span class="special">)...;</span> +<span class="special">}</span> +</pre> +<p> + Now you create a file <code class="literal">main.cpp</code>, which contains the <code class="literal">BOOST_PYTHON_MODULE</code> + 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> + +<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"><span class="preprocessor">#include</span> <span class="special"><</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">></span> +<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">point</span><span class="special">.</span><span class="identifier">h</span><span class="special">></span> +<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">triangle</span><span class="special">.</span><span class="identifier">h</span><span class="special">></span> + +<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"><</span><span class="identifier">point</span><span class="special">>(</span><span class="string">"point"</span><span class="special">)...;</span> + <span class="identifier">class_</span><span class="special"><</span><span class="identifier">triangle</span><span class="special">>(</span><span class="string">"triangle"</span><span class="special">)...;</span> +<span class="special">}</span> +</pre> +<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> +<div class="note"><table border="0" summary="Note"> +<tr> +<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../../../../../doc/src/images/note.png"></td> +<th align="left">Note</th> +</tr> +<tr><td align="left" valign="top"><p> + If you're exporting your classes with <a href="../../../../../pyste/index.html" target="_top">Pyste</a>, + take a look at the <code class="literal">--multiple</code> option, that generates + the wrappers in various files as demonstrated here. + </p></td></tr> +</table></div> +<div class="note"><table border="0" summary="Note"> +<tr> +<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../../../../../doc/src/images/note.png"></td> +<th align="left">Note</th> +</tr> +<tr><td align="left" valign="top"><p> + 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>. + </p></td></tr> +</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"><div class="copyright-footer">Copyright © 2002-2005 Joel + de Guzman, David Abrahams<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></td> +</tr></table> +<hr> +<div class="spirit-nav"> +<a accesskey="p" href="exception.html"><img src="../../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../../../doc/src/images/home.png" alt="Home"></a> +</div> +</body> +</html> diff --git a/libs/python/doc/tutorial/doc/tutorial.qbk b/libs/python/doc/tutorial/doc/tutorial.qbk new file mode 100644 index 000000000..10a452200 --- /dev/null +++ b/libs/python/doc/tutorial/doc/tutorial.qbk @@ -0,0 +1,1985 @@ +[library python + [version 2.0] + [authors [de Guzman, Joel], [Abrahams, David]] + [copyright 2002 2003 2004 2005 Joel de Guzman, David Abrahams] + [category inter-language support] + [purpose + Reflects C++ classes and functions into Python + ] + [license + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + <ulink url="http://www.boost.org/LICENSE_1_0.txt"> + http://www.boost.org/LICENSE_1_0.txt + </ulink>) + ] +] + +[/ QuickBook Document version 0.9 ] + +[def __note__ [$images/note.png]] +[def __alert__ [$images/alert.png]] +[def __tip__ [$images/tip.png]] +[def :-) [$images/smiley.png]] +[def __jam__ [$images/jam.png]] + +[section QuickStart] + +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). + +[h2 Hello World] + +Following C/C++ tradition, let's start with the "hello, world". A C++ +Function: + + char const* greet() + { + return "hello, world"; + } + +can be exposed to Python by writing a Boost.Python wrapper: + + #include <boost/python.hpp> + + BOOST_PYTHON_MODULE(hello_ext) + { + using namespace boost::python; + def("greet", greet); + } + +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: + +[python] + + >>> import hello_ext + >>> print hello_ext.greet() + hello, world + +[c++] + +[:['[*Next stop... Building your Hello World module from start to finish...]]] + +[endsect] +[section:hello Building Hello World] + +[h2 From Start To Finish] + +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 will outline the steps +necessary to achieve that. We will use the build tool that comes bundled +with every boost distribution: [*bjam]. + +[note [*Building without bjam] + +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 [^bjam]. + +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. +] + +We will 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: [@../../../building.html +building.html]. After this brief ['bjam] tutorial, we should have built +the DLLs and run a python program using the extension. + +The tutorial example can be found in the directory: +[^libs/python/example/tutorial]. There, you can find: + +* hello.cpp +* hello.py +* Jamroot + +The [^hello.cpp] file is our C++ hello world example. The [^Jamroot] is +a minimalist ['bjam] script that builds the DLLs for us. Finally, +[^hello.py] is our Python program that uses the extension in +[^hello.cpp]. + +Before anything else, you should have the bjam executable in your boost +directory or somewhere in your path such that [^bjam] 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 +[@http://sourceforge.net/project/showfiles.php?group_id=7586 here]. + +[h2 Let's Jam!] +__jam__ + +[@../../../../example/tutorial/Jamroot Here] is our minimalist Jamroot +file. Simply copy the file and tweak [^use-project boost] to where your +boost root directory is and your OK. + +The comments contained in the Jamrules file above should be sufficient +to get you going. + +[h2 Running bjam] + +['bjam] is run using your operating system's command line interpreter. + +[:Start it up.] + +A file called user-config.jam in your home directory is used to +configure your tools. In Windows, your home directory can be found by +typing: + +[pre +ECHO %HOMEDRIVE%%HOMEPATH% +] + +into a command prompt window. Your file should at least have the rules +for your compiler and your python installation. A specific example of +this on Windows would be: + +[pre +# MSVC configuration +using msvc : 8.0 ; + +# Python configuration +using python : 2.4 : C:/dev/tools/Python/ ; +] + +The first rule tells Bjam to use the MSVC 8.0 compiler and associated +tools. The second rule provides information on Python, its version and +where it is located. The above assumes that the Python installation is +in [^C:/dev/tools\/Python/]. If you have one fairly "standard" python +installation for your platform, you might not need to do this. + +Now we are ready... Be sure to [^cd] to [^libs/python/example/tutorial] +where the tutorial [^"hello.cpp"] and the [^"Jamroot"] is situated. + +Finally: + + bjam + +It should be building now: + +[pre +cd C:\dev\boost\libs\python\example\tutorial +bjam +...patience... +...found 1101 targets... +...updating 35 targets... +] + +And so on... Finally: + +[pre + Creating library /path-to-boost_python.dll/ + Creating library /path-to-'''hello_ext'''.exp/ +'''**passed**''' ... hello.test +...updated 35 targets... +] + +Or something similar. If all is well, you should now have built the DLLs and +run the Python program. + +[:[*There you go... Have fun!]] + +[endsect] +[section:exposing Exposing Classes] + +Now let's expose a C++ class to Python. + +Consider a C++ class/struct that we want to expose to Python: + + struct World + { + void set(std::string msg) { this->msg = msg; } + std::string greet() { return msg; } + std::string msg; + }; + +We can expose this to Python by writing a corresponding Boost.Python +C++ Wrapper: + + #include <boost/python.hpp> + using namespace boost::python; + + BOOST_PYTHON_MODULE(hello) + { + class_<World>("World") + .def("greet", &World::greet) + .def("set", &World::set) + ; + } + +Here, we wrote a C++ class wrapper that exposes the member functions +[^greet] and [^set]. Now, after building our module as a shared library, we +may use our class [^World] in Python. Here's a sample Python session: + +[python] + + >>> import hello + >>> planet = hello.World() + >>> planet.set('howdy') + >>> planet.greet() + 'howdy' + +[section Constructors] + +Our previous example didn't have any explicit constructors. +Since [^World] 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 + + >>> planet = hello.World() + +We may wish to wrap a class with a non-default constructor. Let us +build on our previous example: + +[c++] + + struct World + { + World(std::string msg): msg(msg) {} // added constructor + void set(std::string msg) { this->msg = msg; } + std::string greet() { return msg; } + std::string msg; + }; + +This time [^World] has no default constructor; our previous +wrapping code would fail to compile when the library tried to expose +it. We have to tell [^class_<World>] about the constructor we want to +expose instead. + + #include <boost/python.hpp> + using namespace boost::python; + + BOOST_PYTHON_MODULE(hello) + { + class_<World>("World", init<std::string>()) + .def("greet", &World::greet) + .def("set", &World::set) + ; + } + +[^init<std::string>()] exposes the constructor taking in a +[^std::string] (in Python, constructors are spelled +"[^"__init__"]"). + +We can expose additional constructors by passing more [^init<...>]s to +the [^def()] member function. Say for example we have another World +constructor taking in two doubles: + + class_<World>("World", init<std::string>()) + .def(init<double, double>()) + .def("greet", &World::greet) + .def("set", &World::set) + ; + +On the other hand, if we do not wish to expose any constructors at +all, we may use [^no_init] instead: + + class_<Abstract>("Abstract", no_init) + +This actually adds an [^__init__] method which always raises a +Python RuntimeError exception. + +[endsect] +[section Class Data Members] + +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 [*read-only] or +[*read-write]. Consider this class [^Var]: + + struct Var + { + Var(std::string name) : name(name), value() {} + std::string const name; + float value; + }; + +Our C++ [^Var] class and its data members can be exposed to Python: + + class_<Var>("Var", init<std::string>()) + .def_readonly("name", &Var::name) + .def_readwrite("value", &Var::value); + +Then, in Python, assuming we have placed our Var class inside the namespace +hello as we did before: + +[python] + + >>> x = hello.Var('pi') + >>> x.value = 3.14 + >>> print x.name, 'is around', x.value + pi is around 3.14 + +Note that [^name] is exposed as [*read-only] while [^value] is exposed +as [*read-write]. + + >>> x.name = 'e' # can't change name + Traceback (most recent call last): + File "<stdin>", line 1, in ? + AttributeError: can't set attribute + +[endsect] +[section Class Properties] + +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: + +[c++] + + struct Num + { + Num(); + float get() const; + void set(float value); + ... + }; + +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 +[^Num] class using Boost.Python: + + class_<Num>("Num") + .add_property("rovalue", &Num::get) + .add_property("value", &Num::get, &Num::set); + +And at last, in Python: + +[python] + + >>> x = Num() + >>> x.value = 3.14 + >>> x.value, x.rovalue + (3.14, 3.14) + >>> x.rovalue = 2.17 # error! + +Take note that the class property [^rovalue] is exposed as [*read-only] +since the [^rovalue] setter member function is not passed in: + +[c++] + + .add_property("rovalue", &Num::get) + +[endsect] +[section Inheritance] + +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. + +Consider this trivial inheritance structure: + + struct Base { virtual ~Base(); }; + struct Derived : Base {}; + +And a set of C++ functions operating on [^Base] and [^Derived] object +instances: + + void b(Base*); + void d(Derived*); + Base* factory() { return new Derived; } + +We've seen how we can wrap the base class [^Base]: + + class_<Base>("Base") + /*...*/ + ; + +Now we can inform Boost.Python of the inheritance relationship between +[^Derived] and its base class [^Base]. Thus: + + class_<Derived, bases<Base> >("Derived") + /*...*/ + ; + +Doing so, we get some things for free: + +# Derived automatically inherits all of Base's Python methods + (wrapped C++ member functions) +# [*If] Base is polymorphic, [^Derived] objects which have been passed to + Python via a pointer or reference to [^Base] can be passed where a pointer + or reference to [^Derived] is expected. + +Now, we will expose the C++ free functions [^b] and [^d] and [^factory]: + + def("b", b); + def("d", d); + def("factory", factory); + +Note that free function [^factory] is being used to generate new +instances of class [^Derived]. In such cases, we use +[^return_value_policy<manage_new_object>] to instruct Python to adopt +the pointer to [^Base] and hold the instance in a new Python [^Base] +object until the the Python object is destroyed. We will see more of +Boost.Python [link python.call_policies call policies] later. + + // Tell Python to take ownership of factory's result + def("factory", factory, + return_value_policy<manage_new_object>()); + +[endsect] + +[section Class Virtual Functions] + +In this section, we will learn how to make functions behave polymorphically +through virtual functions. Continuing our example, let us add a virtual function +to our [^Base] class: + + struct Base + { + virtual ~Base() {} + virtual int f() = 0; + }; + +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 +`Base`. Yet, when you have a virtual function that's going to be overridden in +Python and called polymorphically *from C++*, we'll need to add some +scaffoldings to make things work properly. What we'll do is write a class +wrapper that derives from `Base` that will unintrusively hook into the virtual +functions so that a Python override may be called: + + struct BaseWrap : Base, wrapper<Base> + { + int f() + { + return this->get_override("f")(); + } + }; + +Notice too that in addition to inheriting from `Base`, we also multiply- +inherited `wrapper<Base>` (See [@../../../v2/wrapper.html Wrapper]). The +`wrapper` template makes the job of wrapping classes that are meant to +overridden in Python, easier. + +[blurb __alert__ [*MSVC6/7 Workaround] + +If you are using Microsoft Visual C++ 6 or 7, you have to write `f` as: + +`return call<int>(this->get_override("f").ptr());`.] + +BaseWrap's overridden virtual member function `f` in effect calls the +corresponding method of the Python object through `get_override`. + +Finally, exposing `Base`: + + class_<BaseWrap, boost::noncopyable>("Base") + .def("f", pure_virtual(&Base::f)) + ; + +`pure_virtual` signals Boost.Python that the function `f` is a pure virtual +function. + +[note [*member function and methods] + +Python, like many object oriented languages uses the term [*methods]. +Methods correspond roughly to C++'s [*member functions]] + +[endsect] + +[section Virtual Functions with Default Implementations] + +We've seen in the previous section how classes with pure virtual functions are +wrapped using Boost.Python's [@../../../v2/wrapper.html class wrapper] +facilities. If we wish to wrap [*non]-pure-virtual functions instead, the +mechanism is a bit different. + +Recall that in the [link python.class_virtual_functions previous section], we +wrapped a class with a pure virtual function that we then implemented in C++, or +Python classes derived from it. Our base class: + + struct Base + { + virtual int f() = 0; + }; + +had a pure virtual function [^f]. If, however, its member function [^f] was +not declared as pure virtual: + + struct Base + { + virtual ~Base() {} + virtual int f() { return 0; } + }; + +We wrap it this way: + + struct BaseWrap : Base, wrapper<Base> + { + int f() + { + if (override f = this->get_override("f")) + return f(); // *note* + return Base::f(); + } + + int default_f() { return this->Base::f(); } + }; + +Notice how we implemented `BaseWrap::f`. Now, we have to check if there is an +override for `f`. If none, then we call `Base::f()`. + +[blurb __alert__ [*MSVC6/7 Workaround] + +If you are using Microsoft Visual C++ 6 or 7, you have to rewrite the line +with the `*note*` as: + +`return call<char const*>(f.ptr());`.] + +Finally, exposing: + + class_<BaseWrap, boost::noncopyable>("Base") + .def("f", &Base::f, &BaseWrap::default_f) + ; + +Take note that we expose both `&Base::f` and `&BaseWrap::default_f`. +Boost.Python needs to keep track of 1) the dispatch function [^f] and 2) the +forwarding function to its default implementation [^default_f]. There's a +special [^def] function for this purpose. + +In Python, the results would be as expected: + +[python] + + >>> base = Base() + >>> class Derived(Base): + ... def f(self): + ... return 42 + ... + >>> derived = Derived() + +Calling [^base.f()]: + + >>> base.f() + 0 + +Calling [^derived.f()]: + + >>> derived.f() + 42 + +[endsect] +[section Class Operators/Special Functions] + +[h2 Python Operators] + +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. + +Consider a file position class [^FilePos] and a set of operators that take +on FilePos instances: + +[c++] + + class FilePos { /*...*/ }; + + FilePos operator+(FilePos, int); + FilePos operator+(int, FilePos); + int operator-(FilePos, FilePos); + FilePos operator-(FilePos, int); + FilePos& operator+=(FilePos&, int); + FilePos& operator-=(FilePos&, int); + bool operator<(FilePos, FilePos); + +The class and the various operators can be mapped to Python rather easily +and intuitively: + + class_<FilePos>("FilePos") + .def(self + int()) // __add__ + .def(int() + self) // __radd__ + .def(self - self) // __sub__ + .def(self - int()) // __sub__ + .def(self += int()) // __iadd__ + .def(self -= other<int>()) + .def(self < self); // __lt__ + +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 [^self] refers to FilePos object. Also, not every class [^T] that +you might need to interact with in an operator expression is (cheaply) +default-constructible. You can use [^other<T>()] in place of an actual +[^T] instance when writing "self expressions". + +[h2 Special Methods] + +Python has a few more ['Special Methods]. 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 ['special functions]. Example: + + class Rational + { public: operator double() const; }; + + Rational pow(Rational, Rational); + Rational abs(Rational); + ostream& operator<<(ostream&,Rational); + + class_<Rational>("Rational") + .def(float_(self)) // __float__ + .def(pow(self, other<Rational>)) // __pow__ + .def(abs(self)) // __abs__ + .def(str(self)) // __str__ + ; + +Need we say more? + +[note What is the business of `operator<<`? +Well, the method `str` requires the `operator<<` to do its work (i.e. +`operator<<` is used by the method defined by `def(str(self))`.] + +[endsect] +[endsect] [/ Exposing Classes ] + +[section Functions] + +In this chapter, we'll look at Boost.Python powered functions in closer +detail. We will see some facilities to make exposing C++ functions to +Python safe from potential pifalls such as dangling pointers and +references. We will 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. + +[:['Read on...]] + +But before you do, you might want to fire up Python 2.2 or later and type +[^>>> import this]. + +[pre +>>> import this +The Zen of Python, by Tim Peters +Beautiful is better than ugly. +Explicit is better than implicit. +Simple is better than complex. +Complex is better than complicated. +Flat is better than nested. +Sparse is better than dense. +Readability counts. +Special cases aren't special enough to break the rules. +Although practicality beats purity. +Errors should never pass silently. +Unless explicitly silenced. +In the face of ambiguity, refuse the temptation to guess. +There should be one-- and preferably only one --obvious way to do it +Although that way may not be obvious at first unless you're Dutch. +Now is better than never. +Although never is often better than *right* 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! +] + +[section Call Policies] + +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: + + X& f(Y& y, Z* z); + +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 + + >>> x = f(y, z) # x refers to some C++ X + >>> del y + >>> x.some_method() # CRASH! + +What's the problem? + +Well, what if f() was implemented as shown below: + + X& f(Y& y, Z* z) + { + y.z = z; + return y.x; + } + +The problem is that the lifetime of result X& 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. + +Here's what's happening: + +# [^f] is called passing in a reference to [^y] and a pointer to [^z] +# A reference to [^y.x] is returned +# [^y] is deleted. [^x] is a dangling reference +# [^x.some_method()] is called +# [*BOOM!] + +We could copy result into a new object: + +[python] + + >>> f(y, z).set(42) # Result disappears + >>> y.x.get() # No crash, but still bad + 3.14 + +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. + +Our problems do not end there. Suppose Y is implemented as follows: + +[c++] + + struct Y + { + X x; Z* z; + int z_value() { return z->value(); } + }; + +Notice that the data member [^z] is held by class Y using a raw +pointer. Now we have a potential dangling pointer problem inside Y: + + >>> x = f(y, z) # y refers to z + >>> del z # Kill the z object + >>> y.z_value() # CRASH! + +For reference, here's the implementation of [^f] again: + + X& f(Y& y, Z* z) + { + y.z = z; + return y.x; + } + +Here's what's happening: + +# [^f] is called passing in a reference to [^y] and a pointer to [^z] +# A pointer to [^z] is held by [^y] +# A reference to [^y.x] is returned +# [^z] is deleted. [^y.z] is a dangling pointer +# [^y.z_value()] is called +# [^z->value()] is called +# [*BOOM!] + +[h2 Call Policies] + +Call Policies may be used in situations such as the example detailed above. +In our example, [^return_internal_reference] and [^with_custodian_and_ward] +are our friends: + + def("f", f, + return_internal_reference<1, + with_custodian_and_ward<1, 2> >()); + +What are the [^1] and [^2] parameters, you ask? + + return_internal_reference<1 + +Informs Boost.Python that the first argument, in our case [^Y& y], is the +owner of the returned reference: [^X&]. The "[^1]" simply specifies the +first argument. In short: "return an internal reference [^X&] owned by the +1st argument [^Y& y]". + + with_custodian_and_ward<1, 2> + +Informs Boost.Python that the lifetime of the argument indicated by ward +(i.e. the 2nd argument: [^Z* z]) is dependent on the lifetime of the +argument indicated by custodian (i.e. the 1st argument: [^Y& y]). + +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: + + policy1<args..., + policy2<args..., + policy3<args...> > > + +Here is the list of predefined call policies. A complete reference detailing +these can be found [@../../../v2/reference.html#models_of_call_policies here]. + +* [*with_custodian_and_ward]: Ties lifetimes of the arguments +* [*with_custodian_and_ward_postcall]: Ties lifetimes of the arguments and results +* [*return_internal_reference]: Ties lifetime of one argument to that of result +* [*return_value_policy<T> with T one of:] + * [*reference_existing_object]: naive (dangerous) approach + * [*copy_const_reference]: Boost.Python v1 approach + * [*copy_non_const_reference]: + * [*manage_new_object]: Adopt a pointer and hold the instance + +[blurb :-) [*Remember the Zen, Luke:] + +"Explicit is better than implicit" + +"In the face of ambiguity, refuse the temptation to guess" +] + +[endsect] +[section Overloading] + +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. + +We have here our C++ class: + + struct X + { + bool f(int a) + { + return true; + } + + bool f(int a, double b) + { + return true; + } + + bool f(int a, double b, char c) + { + return true; + } + + int f(int a, int b, int c) + { + return a + b + c; + }; + }; + +Class X has 4 overloaded functions. We will start by introducing some +member function pointer variables: + + bool (X::*fx1)(int) = &X::f; + bool (X::*fx2)(int, double) = &X::f; + bool (X::*fx3)(int, double, char)= &X::f; + int (X::*fx4)(int, int, int) = &X::f; + +With these in hand, we can proceed to define and wrap this for Python: + + .def("f", fx1) + .def("f", fx2) + .def("f", fx3) + .def("f", fx4) + +[endsect] +[section Default Arguments] + +Boost.Python wraps (member) function pointers. Unfortunately, C++ function +pointers carry no default argument info. Take a function [^f] with default +arguments: + + int f(int, double = 3.14, char const* = "hello"); + +But the type of a pointer to the function [^f] has no information +about its default arguments: + + int(*g)(int,double,char const*) = f; // defaults lost! + +When we pass this function pointer to the [^def] function, there is no way +to retrieve the default arguments: + + def("f", f); // defaults lost! + +Because of this, when wrapping C++ code, we had to resort to manual +wrapping as outlined in the [link python.overloading previous section], or +writing thin wrappers: + + // write "thin wrappers" + int f1(int x) { return f(x); } + int f2(int x, double y) { return f(x,y); } + + /*...*/ + + // in module init + def("f", f); // all arguments + def("f", f2); // two arguments + def("f", f1); // one argument + +When you want to wrap functions (or member functions) that either: + +* have default arguments, or +* are overloaded with a common sequence of initial arguments + +[h2 BOOST_PYTHON_FUNCTION_OVERLOADS] + +Boost.Python now has a way to make it easier. For instance, given a function: + + int foo(int a, char b = 1, unsigned c = 2, double d = 3) + { + /*...*/ + } + +The macro invocation: + + BOOST_PYTHON_FUNCTION_OVERLOADS(foo_overloads, foo, 1, 4) + +will automatically create the thin wrappers for us. This macro will create +a class [^foo_overloads] that can be passed on to [^def(...)]. The third +and fourth macro argument are the minimum arguments and maximum arguments, +respectively. In our [^foo] function the minimum number of arguments is 1 +and the maximum number of arguments is 4. The [^def(...)] function will +automatically add all the foo variants for us: + + def("foo", foo, foo_overloads()); + +[h2 BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS] + +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. + +Like [^BOOST_PYTHON_FUNCTION_OVERLOADS], +[^BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS] may be used to automatically create +the thin wrappers for wrapping member functions. Let's have an example: + + struct george + { + void + wack_em(int a, int b = 0, char c = 'x') + { + /*...*/ + } + }; + +The macro invocation: + + BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(george_overloads, wack_em, 1, 3) + +will generate a set of thin wrappers for george's [^wack_em] 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 +[^george_overloads] that can then be used as an argument to [^def(...)]: + + .def("wack_em", &george::wack_em, george_overloads()); + +See the [@../../../v2/overloads.html#BOOST_PYTHON_FUNCTION_OVERLOADS-spec overloads reference] +for details. + +[h2 init and optional] + +A similar facility is provided for class constructors, again, with +default arguments or a sequence of overloads. Remember [^init<...>]? For example, +given a class X with a constructor: + + struct X + { + X(int a, char b = 'D', std::string c = "constructor", double d = 0.0); + /*...*/ + } + +You can easily add this constructor to Boost.Python in one shot: + + .def(init<int, optional<char, std::string, double> >()) + +Notice the use of [^init<...>] and [^optional<...>] to signify the default +(optional arguments). + +[endsect] +[section Auto-Overloading] + +It was mentioned in passing in the previous section that +[^BOOST_PYTHON_FUNCTION_OVERLOADS] and [^BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS] +can also be used for overloaded functions and member functions with a +common sequence of initial arguments. Here is an example: + + void foo() + { + /*...*/ + } + + void foo(bool a) + { + /*...*/ + } + + void foo(bool a, int b) + { + /*...*/ + } + + void foo(bool a, int b, char c) + { + /*...*/ + } + +Like in the previous section, we can generate thin wrappers for these +overloaded functions in one-shot: + + BOOST_PYTHON_FUNCTION_OVERLOADS(foo_overloads, foo, 0, 3) + +Then... + + .def("foo", (void(*)(bool, int, char))0, foo_overloads()); + +Notice though that we have a situation now where we have a minimum of zero +(0) arguments and a maximum of 3 arguments. + +[h2 Manual Wrapping] + +It is important to emphasize however that [*the overloaded functions must +have a common sequence of initial arguments]. Otherwise, our scheme above +will not work. If this is not the case, we have to wrap our functions +[link python.overloading manually]. + +Actually, we can mix and match manual wrapping of overloaded functions and +automatic wrapping through [^BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS] and +its sister, [^BOOST_PYTHON_FUNCTION_OVERLOADS]. Following up on our example +presented in the section [link python.overloading on overloading], since the +first 4 overload functins have a common sequence of initial arguments, we +can use [^BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS] to automatically wrap the +first three of the [^def]s and manually wrap just the last. Here's +how we'll do this: + + BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(xf_overloads, f, 1, 4) + +Create a member function pointers as above for both X::f overloads: + + bool (X::*fx1)(int, double, char) = &X::f; + int (X::*fx2)(int, int, int) = &X::f; + +Then... + + .def("f", fx1, xf_overloads()); + .def("f", fx2) + +[endsect] +[endsect] [/ Functions ] + +[section:object Object Interface] + +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 [^object]. We will see in +this chapter how to deal with Python objects. + +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++ [^object]s are as close as possible to Python. This +should minimize the learning curve significantly. + +[$images/python.png] + +[section Basic Interface] + +Class [^object] wraps [^PyObject*]. All the intricacies of dealing with +[^PyObject]s such as managing reference counting are handled by the +[^object] class. C++ object interoperability is seamless. Boost.Python C++ +[^object]s can in fact be explicitly constructed from any C++ object. + +To illustrate, this Python code snippet: + +[python] + + def f(x, y): + if (y == 'foo'): + x[3:7] = 'bar' + else: + x.items += y(3, x) + return x + + def getfunc(): + return f; + +Can be rewritten in C++ using Boost.Python facilities this way: + +[c++] + + object f(object x, object y) { + if (y == "foo") + x.slice(3,7) = "bar"; + else + x.attr("items") += y(3, x); + return x; + } + object getfunc() { + return object(f); + } + +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. + +[endsect] +[section Derived Object types] + +Boost.Python comes with a set of derived [^object] types corresponding to +that of Python's: + +* list +* dict +* tuple +* str +* long_ +* enum + +These derived [^object] types act like real Python types. For instance: + + str(1) ==> "1" + +Wherever appropriate, a particular derived [^object] has corresponding +Python type's methods. For instance, [^dict] has a [^keys()] method: + + d.keys() + +[^make_tuple] is provided for declaring ['tuple literals]. Example: + + make_tuple(123, 'D', "Hello, World", 0.0); + +In C++, when Boost.Python [^object]s are used as arguments to functions, +subtype matching is required. For example, when a function [^f], as +declared below, is wrapped, it will only accept instances of Python's +[^str] type and subtypes. + + void f(str name) + { + object n2 = name.attr("upper")(); // NAME = name.upper() + str NAME = name.upper(); // better + object msg = "%s is bigger than %s" % make_tuple(NAME,name); + } + +In finer detail: + + str NAME = name.upper(); + +Illustrates that we provide versions of the str type's methods as C++ +member functions. + + object msg = "%s is bigger than %s" % make_tuple(NAME,name); + +Demonstrates that you can write the C++ equivalent of [^"format" % x,y,z] +in Python, which is useful since there's no easy way to do that in std C++. + +[blurb + __alert__ [*Beware] the common pitfall of forgetting that the constructors + of most of Python's mutable types make copies, just as in Python. +] + +Python: +[python] + + >>> d = dict(x.__dict__) # copies x.__dict__ + >>> d['whatever'] = 3 # modifies the copy + +C++: +[c++] + + dict d(x.attr("__dict__")); // copies x.__dict__ + d['whatever'] = 3; // modifies the copy + +[h2 class_<T> as objects] + +Due to the dynamic nature of Boost.Python objects, any [^class_<T>] may +also be one of these types! The following code snippet wraps the class +(type) object. + +We can use this to create wrapped instances. Example: + + object vec345 = ( + class_<Vec2>("Vec2", init<double, double>()) + .def_readonly("length", &Point::length) + .def_readonly("angle", &Point::angle) + )(3.0, 4.0); + + assert(vec345.attr("length") == 5.0); + +[endsect] +[section Extracting C++ objects] + +At some point, we will need to get C++ values out of object instances. This +can be achieved with the [^extract<T>] function. Consider the following: + + double x = o.attr("length"); // compile error + +In the code above, we got a compiler error because Boost.Python +[^object] can't be implicitly converted to [^double]s. Instead, what +we wanted to do above can be achieved by writing: + + double l = extract<double>(o.attr("length")); + Vec2& v = extract<Vec2&>(o); + assert(l == v.length()); + +The first line attempts to extract the "length" attribute of the Boost.Python +[^object]. The second line attempts to ['extract] the [^Vec2] object from held +by the Boost.Python [^object]. + +Take note that we said "attempt to" above. What if the Boost.Python [^object] +does not really hold a [^Vec2] type? This is certainly a possibility considering +the dynamic nature of Python [^object]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: + + extract<Vec2&> x(o); + if (x.check()) { + Vec2& v = x(); ... + +__tip__ The astute reader might have noticed that the [^extract<T>] +facility in fact solves the mutable copying problem: + + dict d = extract<dict>(x.attr("__dict__")); + d["whatever"] = 3; // modifies x.__dict__ ! + + +[endsect] +[section Enums] + +Boost.Python has a nifty facility to capture and wrap C++ enums. While +Python has no [^enum] type, we'll often want to expose our C++ enums to +Python as an [^int]. 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: + + enum choice { red, blue }; + +the construct: + + enum_<choice>("choice") + .value("red", red) + .value("blue", blue) + ; + +can be used to expose to Python. The new enum type is created in the +current [^scope()], which is usually the current module. The snippet above +creates a Python class derived from Python's [^int] type which is +associated with the C++ type passed as its first parameter. + +[note [*what is a scope?] + +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 +[@../../../v2/scope.html here].] + +You can access those values in Python as + +[python] + + >>> my_module.choice.red + my_module.choice.red + +where my_module is the module where the enum is declared. You can also +create a new scope around a class: + +[c++] + + scope in_X = class_<X>("X") + .def( ... ) + .def( ... ) + ; + + // Expose X::nested as X.nested + enum_<X::nested>("nested") + .value("red", red) + .value("blue", blue) + ; + +[def Py_Initialize [@http://www.python.org/doc/current/api/initialization.html#l2h-652 Py_Initialize]] +[def Py_Finalize [@http://www.python.org/doc/current/api/initialization.html#l2h-656 Py_Finalize]] +[def Py_XINCREF [@http://www.python.org/doc/current/api/countingRefs.html#l2h-65 Py_XINCREF]] +[def Py_XDECREF [@http://www.python.org/doc/current/api/countingRefs.html#l2h-67 Py_XDECREF]] +[def PyImport_AppendInittab [@http://www.python.org/doc/current/api/importing.html#l2h-137 PyImport_AppendInittab]] +[def PyImport_AddModule [@http://www.python.org/doc/current/api/importing.html#l2h-125 PyImport_AddModule]] +[def PyModule_New [@http://www.python.org/doc/current/api/moduleObjects.html#l2h-591 PyModule_New]] +[def PyModule_GetDict [@http://www.python.org/doc/current/api/moduleObjects.html#l2h-594 PyModule_GetDict]] + +[endsect] + +[section:creating_python_object Creating `boost::python::object` from `PyObject*`] + +When you want a `boost::python::object` to manage a pointer to `PyObject*` pyobj one does: + + boost::python::object o(boost::python::handle<>(pyobj)); + +In this case, the `o` object, manages the `pyobj`, it won’t increase the reference count on construction. + +Otherwise, to use a borrowed reference: + + boost::python::object o(boost::python::handle<>(boost::python::borrowed(pyobj))); + +In this case, `Py_INCREF` is called, so `pyobj` is not destructed when object o goes out of scope. + +[endsect] [/ creating_python_object ] + +[endsect] [/ Object Interface] + +[section Embedding] + +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 ['embed] the Python interpreter +into your C++ program. + +Currently, Boost.Python does not directly support everything you'll need +when embedding. Therefore you'll need to use the +[@http://www.python.org/doc/current/api/api.html Python/C API] 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... :-) + +[h2 Building embedded programs] + +To be able to embed python into your programs, you have to link to +both Boost.Python's as well as Python's own runtime library. + +Boost.Python's library comes in two variants. Both are located +in Boost's [^/libs/python/build/bin-stage] subdirectory. On Windows, the +variants are called [^boost_python.lib] (for release builds) and +[^boost_python_debug.lib] (for debugging). If you can't find the libraries, +you probably haven't built Boost.Python yet. See +[@../../../building.html Building and Testing] on how to do this. + +Python's library can be found in the [^/libs] subdirectory of +your Python directory. On Windows it is called pythonXY.lib where X.Y is +your major Python version number. + +Additionally, Python's [^/include] subdirectory has to be added to your +include path. + +In a Jamfile, all the above boils down to: + +[pre +projectroot c:\projects\embedded_program ; # location of the program + +# bring in the rules for python +SEARCH on python.jam = $(BOOST_BUILD_PATH) ; +include python.jam ; + +exe embedded_program # name of the executable + : #sources + embedded_program.cpp + : # requirements + <find-library>boost_python <library-path>c:\boost\libs\python + $(PYTHON_PROPERTIES) + <library-path>$(PYTHON_LIB_PATH) + <find-library>$(PYTHON_EMBEDDED_LIBRARY) ; +] + +[h2 Getting started] + +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: + +# '''#include''' [^<boost/python.hpp>] + +# Call Py_Initialize() to start the interpreter and create the [^__main__] module. + +# Call other Python C API routines to use the interpreter. + +[/ # Call Py_Finalize() to stop the interpreter and release its resources.] + +[note [*Note that at this time you must not call Py_Finalize() to stop the +interpreter. This may be fixed in a future version of boost.python.] +] + +(Of course, there can be other C++ code between all of these steps.) + +[:['[*Now that we can embed the interpreter in our programs, lets see how to put it to use...]]] + +[section Using the interpreter] + +As you probably already know, objects in Python are reference-counted. +Naturally, the [^PyObject]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 +[@http://www.python.org/doc/current/c-api/refcounting.html by hand]. This is +messy and especially hard to get right in the presence of C++ exceptions. +Fortunately Boost.Python provides the [@../../../v2/handle.html handle] and +[@../../../v2/object.html object] class templates to automate the process. + +[h2 Running Python code] + +Boost.python provides three related functions to run Python code from C++. + + object eval(str expression, object globals = object(), object locals = object()) + object exec(str code, object globals = object(), object locals = object()) + object exec_file(str filename, object globals = object(), object locals = object()) + +eval evaluates the given expression and returns the resulting value. +exec executes the given code (typically a set of statements) returning the result, +and exec_file executes the code contained in the given file. + +The [^globals] and [^locals] 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 +[^__main__] module for both parameters. + +Boost.python provides a function to import a module: + + object import(str name) + +import imports a python module (potentially loading it into the running process +first), and returns it. + +Let's import the [^__main__] module and run some Python code in its namespace: + + object main_module = import("__main__"); + object main_namespace = main_module.attr("__dict__"); + + object ignored = exec("hello = file('hello.txt', 'w')\n" + "hello.write('Hello world!')\n" + "hello.close()", + main_namespace); + +This should create a file called 'hello.txt' in the current directory +containing a phrase that is well-known in programming circles. + +[h2 Manipulating Python objects] + +Often we'd like to have a class to manipulate Python objects. +But we have already seen such a class above, and in the +[@python/object.html previous section]: the aptly named [^object] class +and its derivatives. We've already seen that they can be constructed from +a [^handle]. The following examples should further illustrate this fact: + + object main_module = import("__main__"); + object main_namespace = main_module.attr("__dict__"); + object ignored = exec("result = 5 ** 2", main_namespace); + int five_squared = extract<int>(main_namespace["result"]); + +Here we create a dictionary object for the [^__main__] 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 use eval instead, +which returns the result directly: + + object result = eval("5 ** 2"); + int five_squared = extract<int>(result); + +[h2 Exception handling] + +If an exception occurs in the evaluation of the python expression, +[@../../../v2/errors.html#error_already_set-spec error_already_set] is thrown: + + try + { + object result = eval("5/0"); + // execution will never get here: + int five_divided_by_zero = extract<int>(result); + } + catch(error_already_set const &) + { + // handle the exception in some way + } + +The [^error_already_set] exception class doesn't carry any information in itself. +To find out more about the Python exception that occurred, you need to use the +[@http://www.python.org/doc/api/exceptionHandling.html exception handling functions] +of the Python C API in your catch-statement. This can be as simple as calling +[@http://www.python.org/doc/api/exceptionHandling.html#l2h-70 PyErr_Print()] to +print the exception's traceback to the console, or comparing the type of the +exception with those of the [@http://www.python.org/doc/api/standardExceptions.html +standard exceptions]: + + catch(error_already_set const &) + { + if (PyErr_ExceptionMatches(PyExc_ZeroDivisionError)) + { + // handle ZeroDivisionError specially + } + else + { + // print all other errors to stderr + PyErr_Print(); + } + } + +(To retrieve even more information from the exception you can use some of the other +exception handling functions listed [@http://www.python.org/doc/api/exceptionHandling.html here].) + +[endsect] +[endsect] [/ Embedding] + +[section Iterators] + +In C++, and STL in particular, we see iterators everywhere. Python also has +iterators, but these are two very different beasts. + +[*C++ iterators:] + +* C++ has 5 type categories (random-access, bidirectional, forward, input, output) +* There are 2 Operation categories: reposition, access +* A pair of iterators is needed to represent a (first/last) range. + +[*Python Iterators:] + +* 1 category (forward) +* 1 operation category (next()) +* Raises StopIteration exception at end + +The typical Python iteration protocol: [^[*for y in x...]] is as follows: + +[python] + + iter = x.__iter__() # get iterator + try: + while 1: + y = iter.next() # get each item + ... # process y + except StopIteration: pass # iterator exhausted + +Boost.Python provides some mechanisms to make C++ iterators play along +nicely as Python iterators. What we need to do is to produce +appropriate `__iter__` function from C++ iterators that is compatible +with the Python iteration protocol. For example: + +[c++] + + object get_iterator = iterator<vector<int> >(); + object iter = get_iterator(v); + object first = iter.next(); + +Or for use in class_<>: + + .def("__iter__", iterator<vector<int> >()) + +[*range] + +We can create a Python savvy iterator using the range function: + +* range(start, finish) +* range<Policies,Target>(start, finish) + +Here, start/finish may be one of: + +* member data pointers +* member function pointers +* adaptable function object (use Target parameter) + +[*iterator] + +* iterator<T, Policies>() + +Given a container [^T], iterator is a shortcut that simply calls [^range] +with &T::begin, &T::end. + +Let's put this into action... Here's an example from some hypothetical +bogon Particle accelerator code: + +[python] + + f = Field() + for x in f.pions: + smash(x) + for y in f.bogons: + count(y) + +Now, our C++ Wrapper: + +[c++] + + class_<F>("Field") + .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] + +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: + + raise RuntimeError, 'unidentifiable C++ Exception' + +Users may provide custom translation. Here's an example: + + struct PodBayDoorException; + void translator(PodBayDoorException const& x) { + PyErr_SetString(PyExc_UserWarning, "I'm sorry Dave..."); + } + BOOST_PYTHON_MODULE(kubrick) { + register_exception_translator< + PodBayDoorException>(translator); + ... + +[endsect] +[section:techniques General Techniques] + +Here are presented some useful techniques that you can use while wrapping code with Boost.Python. + +[section Creating Packages] + +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 +[@http://www.python.org/doc/current/tut/node8.html Python Tutorial]. + +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. + +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) +[^sounds]. Our library already has a neat C++ namespace hierarchy, like so: + + sounds::core + sounds::io + sounds::filters + +We would like to present this same hierarchy to the Python user, allowing him +to write code like this: + + import sounds.filters + sounds.filters.echo(...) # echo is a C++ function + +The first step is to write the wrapping code. We have to export each module +separately with Boost.Python, like this: + + /* file core.cpp */ + BOOST_PYTHON_MODULE(core) + { + /* export everything in the sounds::core namespace */ + ... + } + + /* file io.cpp */ + BOOST_PYTHON_MODULE(io) + { + /* export everything in the sounds::io namespace */ + ... + } + + /* file filters.cpp */ + BOOST_PYTHON_MODULE(filters) + { + /* export everything in the sounds::filters namespace */ + ... + } + +Compiling these files will generate the following Python extensions: +[^core.pyd], [^io.pyd] and [^filters.pyd]. + +[note The extension [^.pyd] is used for python extension modules, which +are just shared libraries. Using the default for your system, like [^.so] for +Unix and [^.dll] for Windows, works just as well.] + +Now, we create this directory structure for our Python package: + +[pre +sounds/ + \_\_init\_\_.py + core.pyd + filters.pyd + io.pyd +] + +The file [^\_\_init\_\_.py] is what tells Python that the directory [^sounds/] is +actually a Python package. It can be a empty file, but can also perform some +magic, that will be shown later. + +Now our package is ready. All the user has to do is put [^sounds] into his +[@http://www.python.org/doc/current/tut/node8.html#SECTION008110000000000000000 PYTHONPATH] +and fire up the interpreter: + +[python] + + >>> import sounds.io + >>> import sounds.filters + >>> sound = sounds.io.open('file.mp3') + >>> new_sound = sounds.filters.echo(sound, 1.0) + +Nice heh? + +This is the simplest way to create hierarchies of packages, but it is not very +flexible. What if we want to add a ['pure] 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. + +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: + +[c++] + + /* file core.cpp */ + BOOST_PYTHON_MODULE(_core) + { + ... + /* export everything in the sounds::core namespace */ + } + +Note that we added an underscore to the module name. The filename will have to +be changed to [^_core.pyd] as well, and we do the same to the other extension modules. +Now, we change our package hierarchy like so: + +[pre +sounds/ + \_\_init\_\_.py + core/ + \_\_init\_\_.py + _core.pyd + filters/ + \_\_init\_\_.py + _filters.pyd + io/ + \_\_init\_\_.py + _io.pyd +] + +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: + +[python] + + >>> import sounds.core._core + >>> sounds.core._core.foo(...) + +which is not what we want. But here enters the [^\_\_init\_\_.py] magic: everything +that is brought to the [^\_\_init\_\_.py] namespace can be accessed directly by the +user. So, all we have to do is bring the entire namespace from [^_core.pyd] +to [^core/\_\_init\_\_.py]. So add this line of code to [^sounds/core/\_\_init\_\_.py]: + + from _core import * + +We do the same for the other packages. Now the user accesses the functions and +classes in the extension modules like before: + + >>> import sounds.filters + >>> sounds.filters.echo(...) + +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 ['pure] Python function, +[^echo_noise], to the [^filters] package. This function applies both the +[^echo] and [^noise] filters in sequence in the given [^sound] object. We +create a file named [^sounds/filters/echo_noise.py] and code our function: + + import _filters + def echo_noise(sound): + s = _filters.echo(sound) + s = _filters.noise(sound) + return s + +Next, we add this line to [^sounds/filters/\_\_init\_\_.py]: + + from echo_noise import echo_noise + +And that's it. The user now accesses this function like any other function +from the [^filters] package: + + >>> import sounds.filters + >>> sounds.filters.echo_noise(...) + +[endsect] +[section Extending Wrapped Objects in Python] + +Thanks to Python's flexibility, you can easily add new methods to a class, +even after it was already created: + + >>> class C(object): pass + >>> + >>> # a regular function + >>> def C_str(self): return 'A C instance!' + >>> + >>> # now we turn it in a member function + >>> C.__str__ = C_str + >>> + >>> c = C() + >>> print c + A C instance! + >>> C_str(c) + A C instance! + +Yes, Python rox. :-) + +We can do the same with classes that were wrapped with Boost.Python. Suppose +we have a class [^point] in C++: + +[c++] + + class point {...}; + + BOOST_PYTHON_MODULE(_geom) + { + class_<point>("point")...; + } + +If we are using the technique from the previous session, +[link python.creating_packages Creating Packages], we can code directly +into [^geom/\_\_init\_\_.py]: + +[python] + + from _geom import * + + # a regular function + def point_str(self): + return str((self.x, self.y)) + + # now we turn it into a member function + point.__str__ = point_str + +[*All] point instances created from C++ will also have this member function! +This technique has several advantages: + +* Cut down compile times to zero for these additional functions +* Reduce the memory footprint to virtually zero +* Minimize the need to recompile +* Rapid prototyping (you can move the code to C++ if required without changing the interface) + +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. + + # The one Boost.Python uses for all wrapped classes. + # You can use here any class exported by Boost instead of "point" + BoostPythonMetaclass = point.__class__ + + class injector(object): + class __metaclass__(BoostPythonMetaclass): + def __init__(self, name, bases, dict): + for b in bases: + if type(b) not in (self, type): + for k,v in dict.items(): + setattr(b,k,v) + return type.__init__(self, name, bases, dict) + + # inject some methods in the point foo + class more_point(injector, point): + def __repr__(self): + return 'Point(x=%s, y=%s)' % (self.x, self.y) + def foo(self): + print 'foo!' + +Now let's see how it got: + + >>> print point() + Point(x=10, y=10) + >>> point().foo() + foo! + +Another useful idea is to replace constructors with factory functions: + + _point = point + + def point(x=0, y=0): + return _point(x, y) + +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. + +[endsect] +[section Reducing Compiling Time] + +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: + +[c++] + + /* file point.cpp */ + #include <point.h> + #include <boost/python.hpp> + + void export_point() + { + class_<point>("point")...; + } + + /* file triangle.cpp */ + #include <triangle.h> + #include <boost/python.hpp> + + void export_triangle() + { + class_<triangle>("triangle")...; + } + +Now you create a file [^main.cpp], which contains the [^BOOST_PYTHON_MODULE] +macro, and call the various export functions inside it. + + void export_point(); + void export_triangle(); + + BOOST_PYTHON_MODULE(_geom) + { + export_point(); + export_triangle(); + } + +Compiling and linking together all this files produces the same result as the +usual approach: + + #include <boost/python.hpp> + #include <point.h> + #include <triangle.h> + + BOOST_PYTHON_MODULE(_geom) + { + class_<point>("point")...; + class_<triangle>("triangle")...; + } + +but the memory is kept under control. + +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. + +[note If you're exporting your classes with [@../../../../pyste/index.html Pyste], +take a look at the [^--multiple] option, that generates the wrappers in +various files as demonstrated here.] + +[note This method is useful too if you are getting the error message +['"fatal error C1204:Compiler limit:internal structure overflow"] when compiling +a large source file, as explained in the [@../../../v2/faq.html#c1204 FAQ].] + +[endsect] +[endsect] [/ General Techniques] + + diff --git a/libs/python/doc/tutorial/index.html b/libs/python/doc/tutorial/index.html new file mode 100644 index 000000000..792427772 --- /dev/null +++ b/libs/python/doc/tutorial/index.html @@ -0,0 +1,18 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<!-- Copyright David Abrahams 2006. 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) --> +<html> + <head> + <meta http-equiv="refresh" content="0; URL=doc/html/index.html"> + </head> + <body> + Automatic redirection failed, click this + <a href="doc/html/index.html">link</a> <hr> + <p>© Copyright Beman Dawes, 2001</p> + <p>Distributed under the Boost Software License, Version 1.0. (See + accompanying file <a href="../../../../LICENSE_1_0.txt"> + LICENSE_1_0.txt</a> or copy at + <a href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/LICENSE_1_0.txt</a>)</p> + </body> +</html> |