mirror of
https://github.com/boostorg/python.git
synced 2026-01-21 17:12:22 +00:00
embedding tutorial updates
[SVN r22616]
This commit is contained in:
@@ -38,9 +38,9 @@ Besides bjam, there are of course other ways to get your module built.
|
||||
What's written here should not be taken as "the one and only way".
|
||||
There are of course other build tools apart from <tt>bjam</tt>.
|
||||
|
||||
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
|
||||
Take note however that the preferred build tool for Boost.Python is bjam.
|
||||
There are so many ways to set up the build incorrectly. Experience shows
|
||||
that 90% of the "I can't build Boost.Python" problems come from people
|
||||
who had to use a different tool.
|
||||
</td>
|
||||
</tr>
|
||||
@@ -71,9 +71,7 @@ here</a>.
|
||||
The complete list of bjam pre-built
|
||||
executables can be found <a href="../../../../../tools/build/index.html#Jam">
|
||||
here</a>.</p>
|
||||
<a name="lets_jam_"></a>
|
||||
<h2>Let's Jam!</h2>
|
||||
<p>
|
||||
<a name="let_s_jam_"></a><h2>Let's Jam!</h2><p>
|
||||
<img src="theme/jam.png"></img></p>
|
||||
<p>
|
||||
Here is our minimalist Jamfile:</p>
|
||||
|
||||
@@ -53,6 +53,18 @@ need to create a class wrapper:</p>
|
||||
</span><span class=keyword>int </span><span class=identifier>f</span><span class=special>() { </span><span class=keyword>return </span><span class=identifier>call_method</span><span class=special><</span><span class=keyword>int</span><span class=special>>(</span><span class=identifier>self</span><span class=special>, </span><span class=string>"f"</span><span class=special>); }
|
||||
</span><span class=identifier>PyObject</span><span class=special>* </span><span class=identifier>self</span><span class=special>;
|
||||
};
|
||||
|
||||
|
||||
</span><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>BaseWrap</span><span class=special>(</span><span class=identifier>PyObject</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=identifier>self_</span><span class=special>) {}
|
||||
</span><span class=identifier>BaseWrap</span><span class=special>(</span><span class=identifier>PyObject</span><span class=special>* </span><span class=identifier>self_</span><span class=special>, </span><span class=identifier>Base </span><span class=keyword>const</span><span class=special>& </span><span class=identifier>copy</span><span class=special>)
|
||||
: </span><span class=identifier>Base</span><span class=special>(</span><span class=identifier>copy</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=keyword>int </span><span class=identifier>f</span><span class=special>() { </span><span class=keyword>return </span><span class=identifier>call_method</span><span class=special><</span><span class=keyword>int</span><span class=special>>(</span><span class=identifier>self</span><span class=special>, </span><span class=string>"f"</span><span class=special>); }
|
||||
</span><span class=keyword>int </span><span class=identifier>default_f</span><span class=special>() { </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=identifier>ADDED</span><span class=special>***
|
||||
</span><span class=identifier>PyObject</span><span class=special>* </span><span class=identifier>self</span><span class=special>;
|
||||
};
|
||||
</span></pre></code>
|
||||
<table width="80%" border="0" align="center">
|
||||
<tr>
|
||||
|
||||
@@ -37,7 +37,7 @@ with an example.</p>
|
||||
<p>
|
||||
We have a C++ library that works with sounds: reading and writing various
|
||||
formats, applying filters to the sound data, etc. It is named (conveniently)
|
||||
<tt>sounds</tt>. Our library already has a neat C++ namespace hierarchy, like so: </p>
|
||||
<tt>sounds</tt>. Our library already has a neat C++ namespace hierarchy, like so:</p>
|
||||
<code><pre>
|
||||
<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
|
||||
@@ -59,21 +59,21 @@ separately with Boost.Python, like this:</p>
|
||||
{
|
||||
/* </span><span class=keyword>export </span><span class=identifier>everything </span><span class=identifier>in </span><span class=identifier>the </span><span class=identifier>sounds</span><span class=special>::</span><span class=identifier>core </span><span class=keyword>namespace </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=keyword>export </span><span class=identifier>everything </span><span class=identifier>in </span><span class=identifier>the </span><span class=identifier>sounds</span><span class=special>::</span><span class=identifier>io </span><span class=keyword>namespace </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=keyword>export </span><span class=identifier>everything </span><span class=identifier>in </span><span class=identifier>the </span><span class=identifier>sounds</span><span class=special>::</span><span class=identifier>filters </span><span class=keyword>namespace </span><span class=special>*/
|
||||
...
|
||||
}
|
||||
}
|
||||
</span></pre></code>
|
||||
<p>
|
||||
Compiling these files will generate the following Python extensions:
|
||||
@@ -97,7 +97,7 @@ Now, we create this directory structure for our Python package:</p>
|
||||
</pre></code><p>
|
||||
The file <tt>__init__.py</tt> is what tells Python that the directory <tt>sounds/</tt> is
|
||||
actually a Python package. It can be a empty file, but can also perform some
|
||||
magic, that will be shown later. </p>
|
||||
magic, that will be shown later.</p>
|
||||
<p>
|
||||
Now our package is ready. All the user has to do is put <tt>sounds</tt> into his
|
||||
<a href="http://www.python.org/doc/current/tut/node8.html#SECTION008110000000000000000">
|
||||
@@ -109,7 +109,7 @@ PYTHONPATH</a> and fire up the interpreter:</p>
|
||||
>>> </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></code>
|
||||
<p>
|
||||
Nice heh? </p>
|
||||
Nice heh?</p>
|
||||
<p>
|
||||
This is the simplest way to create hierarchies of packages, but it is not very
|
||||
flexible. What if we want to add a <i>pure</i> Python function to the filters
|
||||
@@ -126,7 +126,7 @@ little. First, we will have to change the name of the extension modules:</p>
|
||||
{
|
||||
...
|
||||
/* </span><span class=keyword>export </span><span class=identifier>everything </span><span class=identifier>in </span><span class=identifier>the </span><span class=identifier>sounds</span><span class=special>::</span><span class=identifier>core </span><span class=keyword>namespace </span><span class=special>*/
|
||||
}
|
||||
}
|
||||
</span></pre></code>
|
||||
<p>
|
||||
Note that we added an underscore to the module name. The filename will have to
|
||||
@@ -147,7 +147,7 @@ Now, we change our package hierarchy like so:</p>
|
||||
</pre></code><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>
|
||||
access the functions in the core module with this syntax:</p>
|
||||
<code><pre>
|
||||
<span class=special>>>> </span><span class=identifier>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>(...)
|
||||
|
||||
@@ -45,8 +45,9 @@ Boost.Python's static link library comes in two variants. Both are located
|
||||
in Boost's <tt>/libs/python/build/bin-stage</tt> subdirectory. On Windows, the
|
||||
variants are called <tt>boost_python.lib</tt> (for release builds) and
|
||||
<tt>boost_python_debug.lib</tt> (for debugging). If you can't find the libraries,
|
||||
you probably haven't built Boost.Python yet. See <a href="../../building.html">
|
||||
Building and Testing</a> on how to do this.</p>
|
||||
you probably haven't built Boost.Python yet. See <a href="../../building.html
|
||||
Building">
|
||||
and Testing</a> on how to do this.</p>
|
||||
<p>
|
||||
Python's static link library can be found in the <tt>/libs</tt> subdirectory of
|
||||
your Python directory. On Windows it is called pythonXY.lib where X.Y is
|
||||
|
||||
@@ -34,7 +34,7 @@ even after it was already created:</p>
|
||||
</span><span class=special>>>> </span><span class=identifier>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=literal>'A C instance!'
|
||||
</span><span class=special>>>>
|
||||
>>> </span>##<span class=identifier>now </span><span class=identifier>we </span><span class=identifier>turn </span><span class=identifier>it </span><span class=identifier>in </span><span class=identifier>a </span><span class=identifier>member </span><span class=identifier>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=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=identifier>c </span><span class=special>= </span><span class=identifier>C</span><span class=special>()
|
||||
>>> </span><span class=identifier>print </span><span class=identifier>c
|
||||
@@ -56,8 +56,8 @@ we have a class <tt>point</tt> in C++:</p>
|
||||
}
|
||||
</span></pre></code>
|
||||
<p>
|
||||
If we are using the technique from the previous session, <a href="creating_packages.html">
|
||||
|
||||
If we are using the technique from the previous session,
|
||||
<a href="creating_packages.html">
|
||||
Creating Packages</a>, we can code directly into <tt>geom/__init__.py</tt>:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>from </span><span class=identifier>_geom </span><span class=identifier>import </span><span class=special>*
|
||||
@@ -65,7 +65,7 @@ Creating Packages</a>, we can code directly into <tt>geom/__init__.py</tt>:</p>
|
||||
</span>##<span class=identifier>a </span><span class=identifier>regular </span><span class=identifier>function
|
||||
</span><span class=identifier>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=identifier>now </span><span class=identifier>we </span><span class=identifier>turn </span><span class=identifier>it </span><span class=identifier>into </span><span class=identifier>a </span><span class=identifier>member </span><span class=identifier>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></code>
|
||||
@@ -76,9 +76,9 @@ This technique has several advantages:</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>
|
||||
<code><pre>
|
||||
##<span class=identifier>The </span><span class=identifier>one </span><span class=identifier>Boost</span><span class=special>.</span><span class=identifier>Python </span><span class=identifier>uses </span><span class=keyword>for </span><span class=identifier>all </span><span class=identifier>wrapped </span><span class=identifier>classes</span><span class=special>.
|
||||
##<span class=identifier>The </span><span class=identifier>one </span><span class=identifier>Boost</span><span class=special>.</span><span class=identifier>Python </span><span class=identifier>uses </span><span class=keyword>for </span><span class=identifier>all </span><span class=identifier>wrapped </span><span class=identifier>classes</span><span class=special>.
|
||||
</span>##<span class=identifier>You </span><span class=identifier>can </span><span class=identifier>use </span><span class=identifier>here </span><span class=identifier>any </span><span class=keyword>class </span><span class=identifier>exported </span><span class=identifier>by </span><span class=identifier>Boost </span><span class=identifier>instead </span><span class=identifier>of </span><span class=string>"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=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>):
|
||||
|
||||
@@ -1439,10 +1439,10 @@ 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/api/refcounts.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] class
|
||||
template to automate the process.
|
||||
Fortunately Boost.Python provides the [@../../v2/handle.html handle] and
|
||||
[@../../v2/object.html object] class templates to automate the process.
|
||||
|
||||
[h2 Reference-counting handles]
|
||||
[h2 Reference-counting handles and objects]
|
||||
|
||||
There are two ways in which a function in the Python/C API can return a
|
||||
[^PyObject*]: as a ['borrowed reference] or as a ['new reference]. Which of
|
||||
@@ -1458,12 +1458,10 @@ The former returns a reference to an already imported module, the latter
|
||||
retrieves a module's namespace dictionary. Let's use them to retrieve the
|
||||
namespace of the [^__main__] module:
|
||||
|
||||
handle<> main_module(borrowed( PyImport_AddModule("__main__") ));
|
||||
handle<> main_namespace(borrowed( PyModule_GetDict(main_module.get()) ));
|
||||
object main_module(
|
||||
handle<>(borrowed(PyImport_AddModule("__main__"))));
|
||||
object main_namespace = main_module.attr("__dict__");
|
||||
|
||||
Because the Python/C API doesn't know anything about [^handle]s, we used
|
||||
the [@../../v2/handle.html#handle-spec-observers get] member function to
|
||||
retrieve the [^PyObject*] from which the [^handle] was constructed.
|
||||
|
||||
For a function returning a ['new reference] we can just create a [^handle]
|
||||
out of the raw [^PyObject*] without wrapping it in a call to borrowed. One
|
||||
@@ -1512,12 +1510,24 @@ For most intents and purposes you can use the namespace dictionary of the
|
||||
We have already seen how to get the [^__main__] module's namespace so let's
|
||||
run some Python code in it:
|
||||
|
||||
handle<> main_module(borrowed( PyImport_AddModule("__main__") ));
|
||||
handle<> main_namespace(borrowed( PyModule_GetDict(main_module.get()) ));
|
||||
handle<>( PyRun_String("hello = file('hello.txt', 'w')\n"
|
||||
"hello.write('Hello world!')\n"
|
||||
"hello.close()", Py_file_input,
|
||||
main_namespace.get(), main_namespace.get()) );
|
||||
object main_module(
|
||||
handle<>(borrowed(PyImport_AddModule("__main__"))));
|
||||
|
||||
object main_namespace = main_module.attr("__dict__");
|
||||
|
||||
handle<>(PyRun_String(
|
||||
|
||||
"hello = file('hello.txt', 'w')\n"
|
||||
"hello.write('Hello world!')\n"
|
||||
"hello.close()"
|
||||
|
||||
, Py_file_input
|
||||
, main_namespace.ptr()
|
||||
, main_namespace.ptr())
|
||||
);
|
||||
|
||||
Because the Python/C API doesn't know anything about [^object]s, we used
|
||||
the object's [^ptr] member function to retrieve the [^PyObject*].
|
||||
|
||||
This should create a file called 'hello.txt' in the current directory
|
||||
containing a phrase that is well-known in programming circles.
|
||||
@@ -1532,24 +1542,39 @@ you want to be a Dr. Frankenstein, always wrap [^PyObject*]s in [^handle]s.
|
||||
It's nice that [^handle] manages the reference counting details for us, but
|
||||
other than that it doesn't do much. Often we'd like to have a more useful
|
||||
class to manipulate Python objects. But we have already seen such a class
|
||||
in the [@object_interface.html previous section]: the aptly named [^object]
|
||||
class and it's derivatives. What we haven't seen, is that they can be
|
||||
constructed from a [^handle]. The following examples should illustrate this
|
||||
fact:
|
||||
above, and in the [@object_interface.html previous section]: the aptly
|
||||
named [^object] class and it's derivatives. We've already seen that they
|
||||
can be constructed from a [^handle]. The following examples should further
|
||||
illustrate this fact:
|
||||
|
||||
handle<> main_module(borrowed( PyImport_AddModule("__main__") ));
|
||||
dict main_namespace(handle<>(borrowed( PyModule_GetDict(main_module.get()) )));
|
||||
handle<>( PyRun_String("result = 5 ** 2", Py_file_input,
|
||||
main_namespace.ptr(), main_namespace.ptr()) );
|
||||
int five_squared = extract<int>( main_namespace["result"] );
|
||||
object main_module(
|
||||
handle<>(borrowed(PyImport_AddModule("__main__"))));
|
||||
|
||||
dict main_namespace(
|
||||
handle<>(borrowed(PyModule_GetDict(main_module.ptr()))));
|
||||
|
||||
handle<>(PyRun_String(
|
||||
|
||||
"result = 5 ** 2"
|
||||
|
||||
, Py_file_input
|
||||
, main_namespace.ptr()
|
||||
, main_namespace.ptr())
|
||||
);
|
||||
|
||||
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 let
|
||||
PyRun_String return the result directly with Py_eval_input:
|
||||
|
||||
object result(handle<>( PyRun_String("5 ** 2", Py_eval_input,
|
||||
main_namespace.ptr(), main_namespace.ptr()) ));
|
||||
object result(handle<>(PyRun_String(
|
||||
"5 ** 2"
|
||||
, Py_eval_input
|
||||
, main_namespace.ptr()
|
||||
, main_namespace.ptr()))
|
||||
);
|
||||
int five_squared = extract<int>(result);
|
||||
|
||||
__note__ [*Note] that [^object]'s member function to return the wrapped
|
||||
@@ -1563,8 +1588,13 @@ If an exception occurs in the execution of some Python code, the PyRun_String fu
|
||||
|
||||
try
|
||||
{
|
||||
object result(handle<>( PyRun_String("5/0", Py_eval_input,
|
||||
main_namespace.ptr(), main_namespace.ptr()) ));
|
||||
object result(handle<>(PyRun_String(
|
||||
"5/0"
|
||||
, Py_eval_input
|
||||
, main_namespace.ptr()
|
||||
, main_namespace.ptr()))
|
||||
);
|
||||
|
||||
// execution will never get here:
|
||||
int five_divided_by_zero = extract<int>(result);
|
||||
}
|
||||
@@ -1592,8 +1622,12 @@ The [^error_already_set] exception class doesn't carry any information in itself
|
||||
|
||||
If you'd rather not have [^handle] throw a C++ exception when it is constructed, you can use the [@../../v2/handle.html#allow_null-spec allow_null] function in the same way you'd use borrowed:
|
||||
|
||||
handle<> result(allow_null( PyRun_String("5/0", Py_eval_input,
|
||||
main_namespace.ptr(), main_namespace.ptr()) ));
|
||||
handle<> result(allow_null(PyRun_String(
|
||||
"5/0"
|
||||
, Py_eval_input
|
||||
, main_namespace.ptr()
|
||||
, main_namespace.ptr())));
|
||||
|
||||
if (!result)
|
||||
// Python exception occurred
|
||||
else
|
||||
@@ -1886,8 +1920,8 @@ we have a class [^point] in C++:
|
||||
class_<point>("point")...;
|
||||
}
|
||||
|
||||
If we are using the technique from the previous session, [@creating_packages.html
|
||||
Creating Packages], we can code directly into [^geom/__init__.py]:
|
||||
If we are using the technique from the previous session,
|
||||
[@creating_packages.html Creating Packages], we can code directly into [^geom/__init__.py]:
|
||||
|
||||
from _geom import *
|
||||
|
||||
|
||||
@@ -32,10 +32,10 @@ class_ definitions in multiple files:</p>
|
||||
<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=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>point</span><span class=special>>(</span><span class=string>"point"</span><span class=special>)...;
|
||||
}
|
||||
|
||||
/* </span><span class=identifier>file </span><span class=identifier>triangle</span><span class=special>.</span><span class=identifier>cpp </span><span class=special>*/
|
||||
@@ -49,11 +49,11 @@ class_ definitions in multiple files:</p>
|
||||
</span></pre></code>
|
||||
<p>
|
||||
Now you create a file <tt>main.cpp</tt>, which contains the <tt>BOOST_PYTHON_MODULE</tt>
|
||||
macro, and call the various export functions inside it. </p>
|
||||
macro, and call the various export functions inside it.</p>
|
||||
<code><pre>
|
||||
<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=identifier>export_point</span><span class=special>();
|
||||
@@ -72,10 +72,10 @@ usual approach:</p>
|
||||
{
|
||||
</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></pre></code>
|
||||
<p>
|
||||
but the memory is kept under control. </p>
|
||||
but the memory is kept under control.</p>
|
||||
<p>
|
||||
This method is recommended too if you are developing the C++ library and
|
||||
exporting it to Python at the same time: changes in a class will only demand
|
||||
@@ -84,7 +84,7 @@ the compilation of a single cpp, instead of the entire wrapper code.</p>
|
||||
<tr>
|
||||
<td class="note_box">
|
||||
<img src="theme/note.gif"></img> If you're exporting your classes with <a href="../../../pyste/index.html">
|
||||
Pyste</a>,
|
||||
Pyste</a>,
|
||||
take a look at the <tt>--multiple</tt> option, that generates the wrappers in
|
||||
various files as demonstrated here. </td>
|
||||
</tr>
|
||||
|
||||
@@ -33,9 +33,10 @@ automatic in Python, the Python/C API requires you to do it
|
||||
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">
|
||||
handle</a> class
|
||||
template to automate the process.</p>
|
||||
<a name="reference_counting_handles"></a><h2>Reference-counting handles</h2><p>
|
||||
handle</a> and
|
||||
<a href="../../v2/object.html">
|
||||
object</a> class templates to automate the process.</p>
|
||||
<a name="reference_counting_handles_and_objects"></a><h2>Reference-counting handles and objects</h2><p>
|
||||
There are two ways in which a function in the Python/C API can return a
|
||||
<tt>PyObject*</tt>: as a <i>borrowed reference</i> or as a <i>new reference</i>. Which of
|
||||
these a function uses, is listed in that function's documentation. The two
|
||||
@@ -53,15 +54,11 @@ The former returns a reference to an already imported module, the latter
|
||||
retrieves a module's namespace dictionary. Let's use them to retrieve the
|
||||
namespace of the <tt>__main__</tt> module:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>handle</span><span class=special><> </span><span class=identifier>main_module</span><span class=special>(</span><span class=identifier>borrowed</span><span class=special>( </span><span class=identifier>PyImport_AddModule</span><span class=special>(</span><span class=string>"__main__"</span><span class=special>) ));
|
||||
</span><span class=identifier>handle</span><span class=special><> </span><span class=identifier>main_namespace</span><span class=special>(</span><span class=identifier>borrowed</span><span class=special>( </span><span class=identifier>PyModule_GetDict</span><span class=special>(</span><span class=identifier>main_module</span><span class=special>.</span><span class=identifier>get</span><span class=special>()) ));
|
||||
<span class=identifier>object </span><span class=identifier>main_module</span><span class=special>(
|
||||
</span><span class=identifier>handle</span><span class=special><>(</span><span class=identifier>borrowed</span><span class=special>(</span><span class=identifier>PyImport_AddModule</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></pre></code>
|
||||
<p>
|
||||
Because the Python/C API doesn't know anything about <tt>handle</tt>s, we used
|
||||
the <a href="../../v2/handle.html#handle-spec-observers">
|
||||
get</a> member function to
|
||||
retrieve the <tt>PyObject*</tt> from which the <tt>handle</tt> was constructed.</p>
|
||||
<p>
|
||||
For a function returning a <i>new reference</i> we can just create a <tt>handle</tt>
|
||||
out of the raw <tt>PyObject*</tt> without wrapping it in a call to borrowed. One
|
||||
such function that returns a new reference is <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55">
|
||||
@@ -120,14 +117,26 @@ For most intents and purposes you can use the namespace dictionary of the
|
||||
We have already seen how to get the <tt>__main__</tt> module's namespace so let's
|
||||
run some Python code in it:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>handle</span><span class=special><> </span><span class=identifier>main_module</span><span class=special>(</span><span class=identifier>borrowed</span><span class=special>( </span><span class=identifier>PyImport_AddModule</span><span class=special>(</span><span class=string>"__main__"</span><span class=special>) ));
|
||||
</span><span class=identifier>handle</span><span class=special><> </span><span class=identifier>main_namespace</span><span class=special>(</span><span class=identifier>borrowed</span><span class=special>( </span><span class=identifier>PyModule_GetDict</span><span class=special>(</span><span class=identifier>main_module</span><span class=special>.</span><span class=identifier>get</span><span class=special>()) ));
|
||||
</span><span class=identifier>handle</span><span class=special><>( </span><span class=identifier>PyRun_String</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>Py_file_input</span><span class=special>,
|
||||
</span><span class=identifier>main_namespace</span><span class=special>.</span><span class=identifier>get</span><span class=special>(), </span><span class=identifier>main_namespace</span><span class=special>.</span><span class=identifier>get</span><span class=special>()) );
|
||||
<span class=identifier>object </span><span class=identifier>main_module</span><span class=special>(
|
||||
</span><span class=identifier>handle</span><span class=special><>(</span><span class=identifier>borrowed</span><span class=special>(</span><span class=identifier>PyImport_AddModule</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>handle</span><span class=special><>(</span><span class=identifier>PyRun_String</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>Py_file_input
|
||||
</span><span class=special>, </span><span class=identifier>main_namespace</span><span class=special>.</span><span class=identifier>ptr</span><span class=special>()
|
||||
, </span><span class=identifier>main_namespace</span><span class=special>.</span><span class=identifier>ptr</span><span class=special>())
|
||||
);
|
||||
</span></pre></code>
|
||||
<p>
|
||||
Because the Python/C API doesn't know anything about <tt>object</tt>s, we used
|
||||
the object's <tt>ptr</tt> member function to retrieve the <tt>PyObject*</tt>.</p>
|
||||
<p>
|
||||
This should create a file called 'hello.txt' in the current directory
|
||||
containing a phrase that is well-known in programming circles.</p>
|
||||
<p>
|
||||
@@ -140,17 +149,28 @@ you want to be a Dr. Frankenstein, always wrap <tt>PyObject*</tt>s in <tt>handle
|
||||
It's nice that <tt>handle</tt> manages the reference counting details for us, but
|
||||
other than that it doesn't do much. Often we'd like to have a more useful
|
||||
class to manipulate Python objects. But we have already seen such a class
|
||||
in the <a href="object_interface.html">
|
||||
previous section</a>: the aptly named <tt>object</tt>
|
||||
class and it's derivatives. What we haven't seen, is that they can be
|
||||
constructed from a <tt>handle</tt>. The following examples should illustrate this
|
||||
fact:</p>
|
||||
above, and in the <a href="object_interface.html">
|
||||
previous section</a>: the aptly
|
||||
named <tt>object</tt> class and it's derivatives. We've already seen that they
|
||||
can be constructed from a <tt>handle</tt>. The following examples should further
|
||||
illustrate this fact:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>handle</span><span class=special><> </span><span class=identifier>main_module</span><span class=special>(</span><span class=identifier>borrowed</span><span class=special>( </span><span class=identifier>PyImport_AddModule</span><span class=special>(</span><span class=string>"__main__"</span><span class=special>) ));
|
||||
</span><span class=identifier>dict </span><span class=identifier>main_namespace</span><span class=special>(</span><span class=identifier>handle</span><span class=special><>(</span><span class=identifier>borrowed</span><span class=special>( </span><span class=identifier>PyModule_GetDict</span><span class=special>(</span><span class=identifier>main_module</span><span class=special>.</span><span class=identifier>get</span><span class=special>()) )));
|
||||
</span><span class=identifier>handle</span><span class=special><>( </span><span class=identifier>PyRun_String</span><span class=special>(</span><span class=string>"result = 5 ** 2"</span><span class=special>, </span><span class=identifier>Py_file_input</span><span class=special>,
|
||||
</span><span class=identifier>main_namespace</span><span class=special>.</span><span class=identifier>ptr</span><span class=special>(), </span><span class=identifier>main_namespace</span><span class=special>.</span><span class=identifier>ptr</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 class=identifier>object </span><span class=identifier>main_module</span><span class=special>(
|
||||
</span><span class=identifier>handle</span><span class=special><>(</span><span class=identifier>borrowed</span><span class=special>(</span><span class=identifier>PyImport_AddModule</span><span class=special>(</span><span class=string>"__main__"</span><span class=special>))));
|
||||
|
||||
</span><span class=identifier>dict </span><span class=identifier>main_namespace</span><span class=special>(
|
||||
</span><span class=identifier>handle</span><span class=special><>(</span><span class=identifier>borrowed</span><span class=special>(</span><span class=identifier>PyModule_GetDict</span><span class=special>(</span><span class=identifier>main_module</span><span class=special>.</span><span class=identifier>ptr</span><span class=special>()))));
|
||||
|
||||
</span><span class=identifier>handle</span><span class=special><>(</span><span class=identifier>PyRun_String</span><span class=special>(
|
||||
|
||||
</span><span class=string>"result = 5 ** 2"
|
||||
|
||||
</span><span class=special>, </span><span class=identifier>Py_file_input
|
||||
</span><span class=special>, </span><span class=identifier>main_namespace</span><span class=special>.</span><span class=identifier>ptr</span><span class=special>()
|
||||
, </span><span class=identifier>main_namespace</span><span class=special>.</span><span class=identifier>ptr</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></code>
|
||||
<p>
|
||||
Here we create a dictionary object for the <tt>__main__</tt> module's namespace.
|
||||
@@ -160,8 +180,12 @@ the dictionary. Another way to achieve the same result is to let
|
||||
PyRun_String</a> return the result directly with <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-58">
|
||||
Py_eval_input</a>:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>object </span><span class=identifier>result</span><span class=special>(</span><span class=identifier>handle</span><span class=special><>( </span><span class=identifier>PyRun_String</span><span class=special>(</span><span class=string>"5 ** 2"</span><span class=special>, </span><span class=identifier>Py_eval_input</span><span class=special>,
|
||||
</span><span class=identifier>main_namespace</span><span class=special>.</span><span class=identifier>ptr</span><span class=special>(), </span><span class=identifier>main_namespace</span><span class=special>.</span><span class=identifier>ptr</span><span class=special>()) ));
|
||||
<span class=identifier>object </span><span class=identifier>result</span><span class=special>(</span><span class=identifier>handle</span><span class=special><>(</span><span class=identifier>PyRun_String</span><span class=special>(
|
||||
</span><span class=string>"5 ** 2"
|
||||
</span><span class=special>, </span><span class=identifier>Py_eval_input
|
||||
</span><span class=special>, </span><span class=identifier>main_namespace</span><span class=special>.</span><span class=identifier>ptr</span><span class=special>()
|
||||
, </span><span class=identifier>main_namespace</span><span class=special>.</span><span class=identifier>ptr</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></code>
|
||||
<p>
|
||||
@@ -176,8 +200,13 @@ error_already_set</a>, so basically, the Python exception is automatically trans
|
||||
<code><pre>
|
||||
<span class=keyword>try
|
||||
</span><span class=special>{
|
||||
</span><span class=identifier>object </span><span class=identifier>result</span><span class=special>(</span><span class=identifier>handle</span><span class=special><>( </span><span class=identifier>PyRun_String</span><span class=special>(</span><span class=string>"5/0"</span><span class=special>, </span><span class=identifier>Py_eval_input</span><span class=special>,
|
||||
</span><span class=identifier>main_namespace</span><span class=special>.</span><span class=identifier>ptr</span><span class=special>(), </span><span class=identifier>main_namespace</span><span class=special>.</span><span class=identifier>ptr</span><span class=special>()) ));
|
||||
</span><span class=identifier>object </span><span class=identifier>result</span><span class=special>(</span><span class=identifier>handle</span><span class=special><>(</span><span class=identifier>PyRun_String</span><span class=special>(
|
||||
</span><span class=string>"5/0"
|
||||
</span><span class=special>, </span><span class=identifier>Py_eval_input
|
||||
</span><span class=special>, </span><span class=identifier>main_namespace</span><span class=special>.</span><span class=identifier>ptr</span><span class=special>()
|
||||
, </span><span class=identifier>main_namespace</span><span class=special>.</span><span class=identifier>ptr</span><span class=special>()))
|
||||
);
|
||||
|
||||
// </span><span class=identifier>execution </span><span class=identifier>will </span><span class=identifier>never </span><span class=identifier>get </span><span class=identifier>here</span><span class=special>:
|
||||
</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>);
|
||||
}
|
||||
@@ -212,8 +241,12 @@ here</a>.)</p>
|
||||
If you'd rather not have <tt>handle</tt> throw a C++ exception when it is constructed, you can use the <a href="../../v2/handle.html#allow_null-spec">
|
||||
allow_null</a> function in the same way you'd use borrowed:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>handle</span><span class=special><> </span><span class=identifier>result</span><span class=special>(</span><span class=identifier>allow_null</span><span class=special>( </span><span class=identifier>PyRun_String</span><span class=special>(</span><span class=string>"5/0"</span><span class=special>, </span><span class=identifier>Py_eval_input</span><span class=special>,
|
||||
</span><span class=identifier>main_namespace</span><span class=special>.</span><span class=identifier>ptr</span><span class=special>(), </span><span class=identifier>main_namespace</span><span class=special>.</span><span class=identifier>ptr</span><span class=special>()) ));
|
||||
<span class=identifier>handle</span><span class=special><> </span><span class=identifier>result</span><span class=special>(</span><span class=identifier>allow_null</span><span class=special>(</span><span class=identifier>PyRun_String</span><span class=special>(
|
||||
</span><span class=string>"5/0"
|
||||
</span><span class=special>, </span><span class=identifier>Py_eval_input
|
||||
</span><span class=special>, </span><span class=identifier>main_namespace</span><span class=special>.</span><span class=identifier>ptr</span><span class=special>()
|
||||
, </span><span class=identifier>main_namespace</span><span class=special>.</span><span class=identifier>ptr</span><span class=special>())));
|
||||
|
||||
</span><span class=keyword>if </span><span class=special>(!</span><span class=identifier>result</span><span class=special>)
|
||||
// </span><span class=identifier>Python </span><span class=identifier>exception </span><span class=identifier>occurred
|
||||
</span><span class=keyword>else
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="deriving_a_python_class.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="class_operators_special_functions.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
Recall that in the <a href="class_virtual_functions.html">
|
||||
@@ -48,18 +48,16 @@ not declared as pure virtual:</p>
|
||||
and instead had a default implementation that returns <tt>0</tt>, as shown above,
|
||||
we need to add a forwarding function that calls the <tt>Base</tt> default virtual
|
||||
function <tt>f</tt> implementation:</p>
|
||||
<pre>
|
||||
<code><span class=keyword>struct </span><span class=identifier>BaseWrap </span><span class=special>: </span><span class=identifier>Base
|
||||
<code><pre>
|
||||
<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>BaseWrap</span><span class=special>(</span><span class=identifier>PyObject</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=identifier>self_</span><span class=special>) {}
|
||||
</span><span class=identifier>BaseWrap</span><span class=special>(</span><span class=identifier>PyObject</span><span class=special>* </span><span class=identifier>self_</span><span class=special>, </span><span class="identifier">Base</span><span class=special> const& </span><span class="identifier">copy</span><span class=special>)
|
||||
: </span><span class=identifier>Base</span><span class=special>(</span><span class="identifier">copy</span><span class=special></span><span class=special>), </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=special> </span><span class=keyword>int </span><span class=identifier>f</span><span class=special>() { </span><span class=keyword>return </span><span class=identifier>call_method</span><span class=special><</span><span class=keyword>int</span><span class=special>>(</span><span class=identifier>self</span><span class=special>, </span><span class=string>"f"</span><span class=special>); }
|
||||
</span><span class=keyword>int </span><span class=identifier>f</span><span class=special>() { </span><span class=keyword>return </span><span class=identifier>call_method</span><span class=special><</span><span class=keyword>int</span><span class=special>>(</span><span class=identifier>self</span><span class=special>, </span><span class=string>"f"</span><span class=special>); }
|
||||
</span><span class=keyword>int </span><span class=identifier>default_f</span><span class=special>() { </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=identifier>ADDED</span><span class=special>***
|
||||
</span><span class=identifier>PyObject</span><span class=special>* </span><span class=identifier>self</span><span class=special>;
|
||||
};
|
||||
</span></code></pre>
|
||||
</span></pre></code>
|
||||
<p>
|
||||
Then, Boost.Python needs to keep track of 1) the dispatch function <tt>f</tt> and
|
||||
2) the forwarding function to its default implementation <tt>default_f</tt>.
|
||||
@@ -112,7 +110,7 @@ Calling <tt>call_f</tt>, passing in a <tt>derived</tt> object:</p>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><a href="deriving_a_python_class.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="class_operators_special_functions.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2002-2003 David Abrahams<br>Copyright © 2002-2003 Joel de Guzman<br><br>
|
||||
|
||||
@@ -132,6 +132,40 @@ test_tutorial()
|
||||
);
|
||||
}
|
||||
|
||||
void
|
||||
test_tutorial2()
|
||||
{
|
||||
using namespace boost::python;
|
||||
|
||||
object main_module(
|
||||
handle<>(borrowed(PyImport_AddModule("__main__"))));
|
||||
|
||||
dict main_namespace(
|
||||
handle<>(borrowed(PyModule_GetDict(main_module.ptr()))));
|
||||
|
||||
handle<>(PyRun_String(
|
||||
|
||||
"result = 5 ** 2"
|
||||
|
||||
, Py_file_input
|
||||
, main_namespace.ptr()
|
||||
, main_namespace.ptr())
|
||||
);
|
||||
|
||||
int five_squared = extract<int>(main_namespace["result"]);
|
||||
assert(five_squared == 25);
|
||||
|
||||
object result(handle<>(
|
||||
PyRun_String("5 ** 2"
|
||||
, Py_eval_input
|
||||
, main_namespace.ptr()
|
||||
, main_namespace.ptr()))
|
||||
);
|
||||
|
||||
int five_squared2 = extract<int>(result);
|
||||
assert(five_squared2 == 25);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
if (python::handle_exception(test))
|
||||
@@ -148,6 +182,13 @@ int main()
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (python::handle_exception(test_tutorial2))
|
||||
{
|
||||
if (PyErr_Occurred())
|
||||
PyErr_Print();
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#include "module_tail.cpp"
|
||||
|
||||
Reference in New Issue
Block a user