mirror of
https://github.com/boostorg/python.git
synced 2026-01-19 16:32:16 +00:00
237 lines
20 KiB
HTML
237 lines
20 KiB
HTML
<html>
|
|
<head>
|
|
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
|
<title>Using the interpreter</title>
|
|
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
|
<link rel="prev" href="embedding.html">
|
|
<link rel="next" href="iterators.html">
|
|
</head>
|
|
<body>
|
|
<table width="100%" height="48" border="0" cellspacing="2">
|
|
<tr>
|
|
<td><img src="theme/c%2B%2Bboost.gif">
|
|
</td>
|
|
<td width="85%">
|
|
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Using the interpreter</b></font>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
<br>
|
|
<table border="0">
|
|
<tr>
|
|
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
|
<td width="30"><a href="embedding.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
<td width="20"><a href="iterators.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
</tr>
|
|
</table>
|
|
<p>
|
|
As you probably already know, objects in Python are reference-counted.
|
|
Naturally, the <tt>PyObject</tt>s of the Python/C API are also reference-counted.
|
|
There is a difference however. While the reference-counting is fully
|
|
automatic in Python, the Python/C API requires you to do it
|
|
<a href="http://www.python.org/doc/current/api/refcounts.html">
|
|
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>
|
|
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
|
|
require slightely different approaches to reference-counting but both can
|
|
be 'handled' by Boost.Python.</p>
|
|
<p>
|
|
For a function returning a <i>borrowed reference</i> we'll have to tell the
|
|
<tt>handle</tt> that the <tt>PyObject*</tt> is borrowed with the aptly named
|
|
<a href="../../v2/handle.html#borrowed-spec">
|
|
borrowed</a> function. Two functions
|
|
returning borrowed references are <a href="http://www.python.org/doc/current/api/importing.html#l2h-125">
|
|
PyImport_AddModule</a> and <a href="http://www.python.org/doc/current/api/moduleObjects.html#l2h-594">
|
|
PyModule_GetDict</a>.
|
|
The former returns a reference to an already imported module, the latter
|
|
retrieves a module's namespace dictionary. Let's use them to retrieve the
|
|
namespace of the <tt>__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></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">
|
|
PyRun_String</a> which we'll
|
|
discuss in the next section.</p>
|
|
<table width="80%" border="0" align="center">
|
|
<tr>
|
|
<td class="note_box">
|
|
<img src="theme/lens.gif"></img> <b>Handle is a class <i>template</i>, so why haven't we been using any template parameters?</b><br>
|
|
<br>
|
|
<tt>handle</tt> has a single template parameter specifying the type of the managed object. This type is <tt>PyObject</tt> 99% of the time, so the parameter was defaulted to <tt>PyObject</tt> for convenience. Therefore we can use the shorthand <tt>handle<></tt> instead of the longer, but equivalent, <tt>handle<PyObject></tt>.
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
<a name="running_python_code"></a><h2>Running Python code</h2><p>
|
|
To run Python code from C++ there is a family of functions in the API
|
|
starting with the PyRun prefix. You can find the full list of these
|
|
functions <a href="http://www.python.org/doc/current/api/veryhigh.html">
|
|
here</a>. They
|
|
all work similarly so we will look at only one of them, namely:</p>
|
|
<code><pre>
|
|
<span class=identifier>PyObject</span><span class=special>* </span><span class=identifier>PyRun_String</span><span class=special>(</span><span class=keyword>char </span><span class=special>*</span><span class=identifier>str</span><span class=special>, </span><span class=keyword>int </span><span class=identifier>start</span><span class=special>, </span><span class=identifier>PyObject </span><span class=special>*</span><span class=identifier>globals</span><span class=special>, </span><span class=identifier>PyObject </span><span class=special>*</span><span class=identifier>locals</span><span class=special>)
|
|
</span></pre></code>
|
|
<p>
|
|
<a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55">
|
|
PyRun_String</a> takes the code to execute as a null-terminated (C-style)
|
|
string in its <tt>str</tt> parameter. The function returns a new reference to a
|
|
Python object. Which object is returned depends on the <tt>start</tt> paramater.</p>
|
|
<p>
|
|
The <tt>start</tt> parameter is the start symbol from the Python grammar to use
|
|
for interpreting the code. The possible values are:</p>
|
|
<table width="90%" border="0" align="center"> <tr>
|
|
<td class="table_title" colspan="6">
|
|
Start symbols </td>
|
|
</tr>
|
|
<tr><tr><td class="table_cells"><a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-58">
|
|
Py_eval_input</a></td><td class="table_cells">for interpreting isolated expressions</td></tr><td class="table_cells"><a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-59">
|
|
Py_file_input</a></td><td class="table_cells">for interpreting sequences of statements</td></tr><td class="table_cells"><a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-60">
|
|
Py_single_input</a></td><td class="table_cells">for interpreting a single statement</td></tr></table>
|
|
<p>
|
|
When using <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-58">
|
|
Py_eval_input</a>, the input string must contain a single expression
|
|
and its result is returned. When using <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-59">
|
|
Py_file_input</a>, the string can
|
|
contain an abitrary number of statements and None is returned.
|
|
<a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-60">
|
|
Py_single_input</a> works in the same way as <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-59">
|
|
Py_file_input</a> but only accepts a
|
|
single statement.</p>
|
|
<p>
|
|
Lastly, the <tt>globals</tt> and <tt>locals</tt> parameters are Python dictionaries
|
|
containing the globals and locals of the context in which to run the code.
|
|
For most intents and purposes you can use the namespace dictionary of the
|
|
<tt>__main__</tt> module for both parameters.</p>
|
|
<p>
|
|
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></pre></code>
|
|
<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>
|
|
<img src="theme/note.gif"></img> <b>Note</b> that we wrap the return value of <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55">
|
|
PyRun_String</a> in a
|
|
(nameless) <tt>handle</tt> even though we are not interested in it. If we didn't
|
|
do this, the the returned object would be kept alive unnecessarily. Unless
|
|
you want to be a Dr. Frankenstein, always wrap <tt>PyObject*</tt>s in <tt>handle</tt>s.</p>
|
|
<a name="beyond_handles"></a><h2>Beyond handles</h2><p>
|
|
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>
|
|
<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>main_namespace </span><span class=identifier>dict</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></pre></code>
|
|
<p>
|
|
Here we create a dictionary object for the <tt>__main__</tt> module's namespace.
|
|
Then we assign 5 squared to the result variable and read this variable from
|
|
the dictionary. Another way to achieve the same result is to let
|
|
<a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55">
|
|
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><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>
|
|
<img src="theme/note.gif"></img> <b>Note</b> that <tt>object</tt>'s member function to return the wrapped
|
|
<tt>PyObject*</tt> is called <tt>ptr</tt> instead of <tt>get</tt>. This makes sense if you
|
|
take into account the different functions that <tt>object</tt> and <tt>handle</tt>
|
|
perform.</p>
|
|
<a name="exception_handling"></a><h2>Exception handling</h2><p>
|
|
If an exception occurs in the execution of some Python code, the <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55">
|
|
PyRun_String</a> function returns a null pointer. Constructing a <tt>handle</tt> out of this null pointer throws <a href="../../v2/errors.html#error_already_set-spec">
|
|
error_already_set</a>, so basically, the Python exception is automatically translated into a C++ exception when using <tt>handle</tt>:</p>
|
|
<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>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>);
|
|
}
|
|
</span><span class=keyword>catch</span><span class=special>(</span><span class=identifier>error_already_set</span><span class=special>)
|
|
{
|
|
// </span><span class=identifier>handle </span><span class=identifier>the </span><span class=identifier>exception </span><span class=identifier>in </span><span class=identifier>some </span><span class=identifier>way
|
|
</span><span class=special>}
|
|
</span></pre></code>
|
|
<p>
|
|
The <tt>error_already_set</tt> exception class doesn't carry any information in itself. To find out more about the Python exception that occurred, you need to use the <a href="http://www.python.org/doc/api/exceptionHandling.html">
|
|
exception handling functions</a> of the Python/C API in your catch-statement. This can be as simple as calling <a href="http://www.python.org/doc/api/exceptionHandling.html#l2h-70">
|
|
PyErr_Print()</a> to print the exception's traceback to the console, or comparing the type of the exception with those of the <a href="http://www.python.org/doc/api/standardExceptions.html">
|
|
standard exceptions</a>:</p>
|
|
<code><pre>
|
|
<span class=keyword>catch</span><span class=special>(</span><span class=identifier>error_already_set</span><span class=special>)
|
|
{
|
|
</span><span class=keyword>if </span><span class=special>(</span><span class=identifier>PyErr_ExceptionMatches</span><span class=special>(</span><span class=identifier>PyExc_ZeroDivisionError</span><span class=special>))
|
|
{
|
|
// </span><span class=identifier>handle </span><span class=identifier>ZeroDivisionError </span><span class=identifier>specially
|
|
</span><span class=special>}
|
|
</span><span class=keyword>else
|
|
</span><span class=special>{
|
|
// </span><span class=identifier>print </span><span class=identifier>all </span><span class=identifier>other </span><span class=identifier>errors </span><span class=identifier>to </span><span class=identifier>stderr
|
|
</span><span class=identifier>PyErr_Print</span><span class=special>();
|
|
}
|
|
}
|
|
</span></pre></code>
|
|
<p>
|
|
(To retrieve even more information from the exception you can use some of the other exception handling functions listed <a href="http://www.python.org/doc/api/exceptionHandling.html">
|
|
here</a>.)</p>
|
|
<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><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
|
|
</span><span class=comment>// everything went okay, it's safe to use the result
|
|
</span></pre></code>
|
|
<table border="0">
|
|
<tr>
|
|
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
|
<td width="30"><a href="embedding.html"><img src="theme/l_arr.gif" border="0"></a></td>
|
|
<td width="20"><a href="iterators.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
|
</tr>
|
|
</table>
|
|
<br>
|
|
<hr size="1"><p class="copyright">Copyright © 2002-2003 Dirk Gerrits<br><br>
|
|
<font size="2">Permission to copy, use, modify, sell and distribute this document
|
|
is granted provided this copyright notice appears in all copies. This document
|
|
is provided "as is" without express or implied warranty, and with
|
|
no claim as to its suitability for any purpose. </font> </p>
|
|
</body>
|
|
</html>
|