2
0
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:
Joel de Guzman
2004-04-07 02:26:36 +00:00
parent 7d632ab3dd
commit b627f93cf1
10 changed files with 218 additions and 101 deletions

View File

@@ -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 &quot;I can't build Boost.Python&quot; 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 &quot;I can't build Boost.Python&quot; 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>

View File

@@ -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>&lt;</span><span class=keyword>int</span><span class=special>&gt;(</span><span class=identifier>self</span><span class=special>, </span><span class=string>&quot;f&quot;</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>&amp; </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>&lt;</span><span class=keyword>int</span><span class=special>&gt;(</span><span class=identifier>self</span><span class=special>, </span><span class=string>&quot;f&quot;</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>(); } // &lt;&lt;=== ***</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>

View File

@@ -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>
&gt;&gt;&gt; </span><span class=identifier>new_sound </span><span class=special>= </span><span class=identifier>sounds</span><span class=special>.</span><span class=identifier>filters</span><span class=special>.</span><span class=identifier>echo</span><span class=special>(</span><span class=identifier>sound</span><span class=special>, </span><span class=number>1.0</span><span class=special>)
</span></pre></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>&gt;&gt;&gt; </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>&gt;&gt;&gt; </span><span class=identifier>sounds</span><span class=special>.</span><span class=identifier>core</span><span class=special>.</span><span class=identifier>_core</span><span class=special>.</span><span class=identifier>foo</span><span class=special>(...)

View File

@@ -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

View File

@@ -34,7 +34,7 @@ even after it was already created:</p>
</span><span class=special>&gt;&gt;&gt; </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>&gt;&gt;&gt;
&gt;&gt;&gt; </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>&gt;&gt;&gt; </span><span class=identifier>C</span><span class=special>.</span><span class=identifier>__str__ </span><span class=special>= </span><span class=identifier>C_str
</span><span class=special>&gt;&gt;&gt; </span><span class=identifier>C</span><span class=special>.</span><span class=identifier>__str__ </span><span class=special>= </span><span class=identifier>C_str
</span><span class=special>&gt;&gt;&gt;
&gt;&gt;&gt; </span><span class=identifier>c </span><span class=special>= </span><span class=identifier>C</span><span class=special>()
&gt;&gt;&gt; </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 &quot;injects&quot; 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>&quot;point&quot;
</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>):

View File

@@ -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 *

View File

@@ -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>&lt;</span><span class=identifier>point</span><span class=special>.</span><span class=identifier>h</span><span class=special>&gt;
</span><span class=preprocessor>#include </span><span class=special>&lt;</span><span class=identifier>boost</span><span class=special>/</span><span class=identifier>python</span><span class=special>.</span><span class=identifier>hpp</span><span class=special>&gt;
</span><span class=keyword>void </span><span class=identifier>export_point</span><span class=special>()
{
</span><span class=identifier>class_</span><span class=special>&lt;</span><span class=identifier>point</span><span class=special>&gt;(</span><span class=string>&quot;point&quot;</span><span class=special>)...;
</span><span class=identifier>class_</span><span class=special>&lt;</span><span class=identifier>point</span><span class=special>&gt;(</span><span class=string>&quot;point&quot;</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>&lt;</span><span class=identifier>point</span><span class=special>&gt;(</span><span class=string>&quot;point&quot;</span><span class=special>)...;
</span><span class=identifier>class_</span><span class=special>&lt;</span><span class=identifier>triangle</span><span class=special>&gt;(</span><span class=string>&quot;triangle&quot;</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>

View File

@@ -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>&lt;&gt; </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>&quot;__main__&quot;</span><span class=special>) ));
</span><span class=identifier>handle</span><span class=special>&lt;&gt; </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>&lt;&gt;(</span><span class=identifier>borrowed</span><span class=special>(</span><span class=identifier>PyImport_AddModule</span><span class=special>(</span><span class=string>&quot;__main__&quot;</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>&quot;__dict__&quot;</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>&lt;&gt; </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>&quot;__main__&quot;</span><span class=special>) ));
</span><span class=identifier>handle</span><span class=special>&lt;&gt; </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>&lt;&gt;( </span><span class=identifier>PyRun_String</span><span class=special>(</span><span class=string>&quot;hello = file('hello.txt', 'w')\n&quot;
</span><span class=string>&quot;hello.write('Hello world!')\n&quot;
</span><span class=string>&quot;hello.close()&quot;</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>&lt;&gt;(</span><span class=identifier>borrowed</span><span class=special>(</span><span class=identifier>PyImport_AddModule</span><span class=special>(</span><span class=string>&quot;__main__&quot;</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>&quot;__dict__&quot;</span><span class=special>);
</span><span class=identifier>handle</span><span class=special>&lt;&gt;(</span><span class=identifier>PyRun_String</span><span class=special>(
</span><span class=string>&quot;hello = file('hello.txt', 'w')\n&quot;
</span><span class=string>&quot;hello.write('Hello world!')\n&quot;
</span><span class=string>&quot;hello.close()&quot;
</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>&lt;&gt; </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>&quot;__main__&quot;</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>&lt;&gt;(</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>&lt;&gt;( </span><span class=identifier>PyRun_String</span><span class=special>(</span><span class=string>&quot;result = 5 ** 2&quot;</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>&lt;</span><span class=keyword>int</span><span class=special>&gt;( </span><span class=identifier>main_namespace</span><span class=special>[</span><span class=string>&quot;result&quot;</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>&lt;&gt;(</span><span class=identifier>borrowed</span><span class=special>(</span><span class=identifier>PyImport_AddModule</span><span class=special>(</span><span class=string>&quot;__main__&quot;</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>&lt;&gt;(</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>&lt;&gt;(</span><span class=identifier>PyRun_String</span><span class=special>(
</span><span class=string>&quot;result = 5 ** 2&quot;
</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>&lt;</span><span class=keyword>int</span><span class=special>&gt;(</span><span class=identifier>main_namespace</span><span class=special>[</span><span class=string>&quot;result&quot;</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>&lt;&gt;( </span><span class=identifier>PyRun_String</span><span class=special>(</span><span class=string>&quot;5 ** 2&quot;</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>&lt;&gt;(</span><span class=identifier>PyRun_String</span><span class=special>(
</span><span class=string>&quot;5 ** 2&quot;
</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>&lt;</span><span class=keyword>int</span><span class=special>&gt;(</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>&lt;&gt;( </span><span class=identifier>PyRun_String</span><span class=special>(</span><span class=string>&quot;5/0&quot;</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>&lt;&gt;(</span><span class=identifier>PyRun_String</span><span class=special>(
</span><span class=string>&quot;5/0&quot;
</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>&lt;</span><span class=keyword>int</span><span class=special>&gt;(</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>&lt;&gt; </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>&quot;5/0&quot;</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>&lt;&gt; </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>&quot;5/0&quot;
</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

View File

@@ -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&amp; </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>&lt;</span><span class=keyword>int</span><span class=special>&gt;(</span><span class=identifier>self</span><span class=special>, </span><span class=string>&quot;f&quot;</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>&lt;</span><span class=keyword>int</span><span class=special>&gt;(</span><span class=identifier>self</span><span class=special>, </span><span class=string>&quot;f&quot;</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>(); } // &lt;&lt;=== ***</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 &copy; 2002-2003 David Abrahams<br>Copyright &copy; 2002-2003 Joel de Guzman<br><br>

View File

@@ -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"