mirror of
https://github.com/boostorg/python.git
synced 2026-01-25 06:22:15 +00:00
Applied proposed changes.
[SVN r1072]
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
|
||||
<title>Embedding</title>
|
||||
<link rel="stylesheet" href="theme/style.css" type="text/css">
|
||||
<link rel="next" href="embedding_basics.html">
|
||||
<link rel="next" href="using_the_interpreter.html">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" background="theme/bkd2.gif" cellspacing="2">
|
||||
@@ -21,27 +21,55 @@
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><img src="theme/l_arr_disabled.gif" border="0"></td>
|
||||
<td width="20"><a href="embedding_basics.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="using_the_interpreter.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<a name="getting_started"></a><h2>Getting started</h2><p>
|
||||
By now you should know how to use Boost.Python to call your C++ code from Python. However sometimes you might need to do the reverse: call Python code from the C++-side. This requires you to 'embed' the Python interpreter in your C++ program. For this we need to use the <a href="http://www.python.org/doc/current/api/api.html">
|
||||
Python C API</a>.</p>
|
||||
<p>
|
||||
To get started you'll need to follow these simple steps:</p>
|
||||
<ol><li>You need to make sure that your program links with <tt>pythonXY.lib</tt> where X.Y is your Python version number. You'll typically find this library in the <tt>/libs</tt> subdirectory of your Python installation.<br><br></li><li>Your program must #include <tt>"Python.h"</tt>. You'll need to add Python's <tt>/include</tt> subdirectory to your include path for this.<br><br></li><li>Call <a href="http://www.python.org/doc/current/api/initialization.html#l2h-652">
|
||||
Py_Initialize</a>() to start the Python interpreter. Also creates the <tt>__main__</tt> module.<br><br></li><li>Call other Python C API routines.<br><br></li><li>Call <a href="http://www.python.org/doc/current/api/initialization.html#l2h-656">
|
||||
Py_Finalize</a>() to stop the Python interpreter and release its resources.</li></ol><p>
|
||||
Of course, there can be other C++ code between all of these steps.</p>
|
||||
<blockquote><p><b>TODO:</b> <tt>Perhaps there should be a template Jamfile for embedding? Then we can put (a link to) it here.</tt></p></blockquote><blockquote><p><i><b>Now that we can embed the interpreter in our programs, lets see how to put it to use...</b></i></p></blockquote><table border="0">
|
||||
By now you should know how to use Boost.Python to call your C++ code from Python. However, sometimes you may need to do the reverse: call Python code from the C++-side. This requires you to <i>embed</i> the Python interpreter into your C++ program. </p>
|
||||
<p>
|
||||
Currently, Boost.Python does not directly support everything you'll need when embedding. Therefore you'll need to use the <a href="http://www.python.org/doc/current/api/api.html">
|
||||
Python/C API</a> to fill in the gaps. However, Boost.Python already makes embedding a lot easier and, in a future version, it may become unnecessary to touch the Python/C API at all. So stay tuned... <img src="theme/smiley.gif"></img></p>
|
||||
<a name="building_embedded_programs"></a><h2>Building embedded programs</h2><p>
|
||||
To be able to use embedding in your programs, they have to be linked to both Boost.Python's and Python's static link library. </p>
|
||||
<p>
|
||||
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>
|
||||
<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 your major Python version number. </p>
|
||||
<p>
|
||||
Additionally, Python's <tt>/include</tt> subdirectory has to be added to your include path.</p>
|
||||
<p>
|
||||
In a Jamfile, all the above boils down to:</p>
|
||||
<code><pre>
|
||||
projectroot c:\projects\embedded_program ; # location of the program
|
||||
|
||||
# bring in the rules for python
|
||||
SEARCH on python.jam = $(BOOST_BUILD_PATH) ;
|
||||
include python.jam ;
|
||||
|
||||
exe embedded_program # name of the executable
|
||||
: #sources
|
||||
embedded_program.cpp
|
||||
: # requirements
|
||||
<find-library>boost_python <library-path>c:\boost\libs\python
|
||||
$(PYTHON_PROPERTIES)
|
||||
<library-path>$(PYTHON_LIB_PATH)
|
||||
<find-library>$(PYTHON_EMBEDDED_LIBRARY) ;
|
||||
</pre></code><a name="getting_started"></a><h2>Getting started</h2><p>
|
||||
Being able to build is nice, but there is nothing to build yet. Embedding the Python interpreter into one of your C++ programs requires these 4 steps:</p>
|
||||
<ol><li>#include <tt><boost/python.hpp></tt><br><br></li><li>Call <a href="http://www.python.org/doc/current/api/initialization.html#l2h-652">
|
||||
Py_Initialize</a>() to start the interpreter and create the <tt>__main__</tt> module.<br><br></li><li>Call other Python C API routines to use the interpreter.<br><br></li><li>Call <a href="http://www.python.org/doc/current/api/initialization.html#l2h-656">
|
||||
Py_Finalize</a>() to stop the interpreter and release its resources.</li></ol><p>
|
||||
(Of course, there can be other C++ code between all of these steps.)</p>
|
||||
<blockquote><p><i><b>Now that we can embed the interpreter in our programs, lets see how to put it to use...</b></i></p></blockquote><table border="0">
|
||||
<tr>
|
||||
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
|
||||
<td width="30"><img src="theme/l_arr_disabled.gif" border="0"></td>
|
||||
<td width="20"><a href="embedding_basics.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
<td width="20"><a href="using_the_interpreter.html"><img src="theme/r_arr.gif" border="0"></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<hr size="1"><p class="copyright">Copyright © 2002 Dirk Gerrits <br><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
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
|
||||
[/ this probably needs to be merged into quickstart.txt ]
|
||||
|
||||
[def __note__ [$theme/note.gif]]
|
||||
[def __alert__ [$theme/alert.gif]]
|
||||
[def __detail__ [$theme/lens.gif]]
|
||||
[def __tip__ [$theme/bulb.gif]]
|
||||
[def :-) [$theme/smiley.gif]]
|
||||
[def Py_Initialize [@http://www.python.org/doc/current/api/initialization.html#l2h-652 Py_Initialize]]
|
||||
[def Py_Finalize [@http://www.python.org/doc/current/api/initialization.html#l2h-656 Py_Finalize]]
|
||||
@@ -15,73 +18,89 @@
|
||||
[def Py_XDECREF [@http://www.python.org/doc/current/api/countingRefs.html#l2h-67 Py_XDECREF]]
|
||||
[def PyImport_AppendInittab [@http://www.python.org/doc/current/api/importing.html#l2h-137 PyImport_AppendInittab]]
|
||||
[def PyImport_AddModule [@http://www.python.org/doc/current/api/importing.html#l2h-125 PyImport_AddModule]]
|
||||
[def PyModule_New [@http://www.python.org/doc/current/api/moduleObjects.html#l2h-591 PyModule_New]]
|
||||
[def PyModule_GetDict [@http://www.python.org/doc/current/api/moduleObjects.html#l2h-594 PyModule_GetDict]]
|
||||
[def handle [@../../v2/handle.html handle]]
|
||||
|
||||
[page:0 Embedding]
|
||||
|
||||
By now you should know how to use Boost.Python to call your C++ code from Python. However, sometimes you may need to do the reverse: call Python code from the C++-side. This requires you to ['embed] the Python interpreter into your C++ program.
|
||||
|
||||
Currently, Boost.Python does not directly support everything you'll need when embedding. Therefore you'll need to use the [@http://www.python.org/doc/current/api/api.html Python/C API] to fill in the gaps. However, Boost.Python already makes embedding a lot easier and, in a future version, it may become unnecessary to touch the Python/C API at all. So stay tuned... :-)
|
||||
|
||||
[h2 Building embedded programs]
|
||||
|
||||
To be able to use embedding in your programs, they have to be linked to both Boost.Python's and Python's static link library.
|
||||
|
||||
Boost.Python's static link library comes in two variants. Both are located in Boost's [^/libs/python/build/bin-stage] subdirectory. On Windows, the variants are called [^boost_python.lib] (for release builds) and [^boost_python_debug.lib] (for debugging). If you can't find the libraries, you probably haven't built Boost.Python yet. See [@../../building.html Building and Testing] on how to do this.
|
||||
|
||||
Python's static link library can be found in the [^/libs] subdirectory of your Python directory. On Windows it is called pythonXY.lib where X.Y is your major Python version number.
|
||||
|
||||
Additionally, Python's [^/include] subdirectory has to be added to your include path.
|
||||
|
||||
In a Jamfile, all the above boils down to:
|
||||
|
||||
[pre
|
||||
projectroot c:\projects\embedded_program ; # location of the program
|
||||
|
||||
# bring in the rules for python
|
||||
SEARCH on python.jam = $(BOOST_BUILD_PATH) ;
|
||||
include python.jam ;
|
||||
|
||||
exe embedded_program # name of the executable
|
||||
: #sources
|
||||
embedded_program.cpp
|
||||
: # requirements
|
||||
<find-library>boost_python <library-path>c:\boost\libs\python
|
||||
$(PYTHON_PROPERTIES)
|
||||
<library-path>$(PYTHON_LIB_PATH)
|
||||
<find-library>$(PYTHON_EMBEDDED_LIBRARY) ;
|
||||
]
|
||||
|
||||
[h2 Getting started]
|
||||
|
||||
By now you should know how to use Boost.Python to call your C++ code from Python. However sometimes you might need to do the reverse: call Python code from the C++-side. This requires you to 'embed' the Python interpreter in your C++ program. For this we need to use the [@http://www.python.org/doc/current/api/api.html Python C API].
|
||||
Being able to build is nice, but there is nothing to build yet. Embedding the Python interpreter into one of your C++ programs requires these 4 steps:
|
||||
|
||||
To get started you'll need to follow these simple steps:
|
||||
# '''#include''' [^<boost/python.hpp>][br][br]
|
||||
|
||||
# You need to make sure that your program links with [^pythonXY.lib] where X.Y is your Python version number. You'll typically find this library in the [^/libs] subdirectory of your Python installation.[br][br]
|
||||
# Call Py_Initialize() to start the interpreter and create the [^__main__] module.[br][br]
|
||||
|
||||
# Your program must '''#include''' [^"Python.h"]. You'll need to add Python's [^/include] subdirectory to your include path for this.[br][br]
|
||||
# Call other Python C API routines to use the interpreter.[br][br]
|
||||
|
||||
# Call Py_Initialize() to start the Python interpreter. Also creates the [^__main__] module.[br][br]
|
||||
# Call Py_Finalize() to stop the interpreter and release its resources.
|
||||
|
||||
# Call other Python C API routines.[br][br]
|
||||
|
||||
# Call Py_Finalize() to stop the Python interpreter and release its resources.
|
||||
|
||||
Of course, there can be other C++ code between all of these steps.
|
||||
|
||||
[:[*TODO:] [^Perhaps there should be a template Jamfile for embedding? Then we can put (a link to) it here.]]
|
||||
(Of course, there can be other C++ code between all of these steps.)
|
||||
|
||||
[:['[*Now that we can embed the interpreter in our programs, lets see how to put it to use...]]]
|
||||
|
||||
[page:1 Embedding basics]
|
||||
[page:1 Using the interpreter]
|
||||
|
||||
[h2 Manual reference counting]
|
||||
As you probably already know, objects in Python are reference-counted. Naturally, the PyObjects of the Python/C API are also reference-counted. There is a difference however. While the reference-counting is fully automatic in Python, the Python/C API requires you to do it [@http://www.python.org/doc/current/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.
|
||||
|
||||
Most things in Python are objects. Therefore it is only natural that many of the Python C API functions operate on Python objects. Because C/C++ can't work with Python objects directly, the API defines a PyObject structure and a lot of functions to operate on PyObject pointers.
|
||||
[h2 Reference-counting handles]
|
||||
|
||||
An important property of Python objects, and therefore of PyObjects, is that they are reference counted. This has major advantages compared to 'dumb' copying: it requiring less memory and it avoids unnecessary copying overhead. However, there is a downside as well. Although the reference counting is transparent from the Python-side, it is quite explicit in the C API. In other words you must increase and decrease the reference counts of PyObjects [*manually] using the Py_XINCREF and Py_XDECREF macros. This is cumbersome, and if you don't do it properly some objects might be released when you still need them, or not be released at all.
|
||||
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 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.
|
||||
|
||||
I will briefly explain how to update the reference counts correctly, but I'll soon show a better way to do things.
|
||||
For a function returning a ['borrowed reference] we'll have to tell the handle that the PyObject pointer is borrowed with the aptly named [@../../v2/handle.html#borrowed-spec borrowed] function. Two functions returning borrowed references are PyImport_AddModule and PyModule_GetDict. 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:
|
||||
|
||||
The API functions that return PyObject pointers are listed in the Python C API documentation as either returning a ['borrowed] or a ['new] reference. The difference is in ['reference ownership].
|
||||
handle<> main_module(borrowed( PyImport_AddModule("__main__") ));
|
||||
handle<> main_namespace(borrowed( PyModule_GetDict(main_module.get()) ));
|
||||
|
||||
When a ['new] reference is returned, you own that reference. Therefore you don't need to worry about the object being deallocated while you still need it. You do need to decrease the reference count when you are done with it however, otherwise the object will never be deallocated: you'll have a ['resource leak].
|
||||
Because the Python/C API doesn't know anything about handles, we used the [@../../v2/handle.html#handle-spec-observers get] member function to retrieve the PyObject pointer from which the handle was constructed.
|
||||
|
||||
Here's a simple example:
|
||||
For a function returning a ['new reference] we can just create a handle out of the raw PyObject pointer without wrapping it in a call to borrowed. One such function that returns a new reference is PyRun_String which we'll discuss in the next section.
|
||||
|
||||
// Create a new tuple of 3 elements long
|
||||
PyObject* my_tuple = PyTuple_New(3);
|
||||
... // Use my_tuple here
|
||||
// We're done with the tuple
|
||||
Py_XDECREF(my_tuple);
|
||||
[blurb __detail__ [*Handle is a class ['template], so why haven't we been using any template parameters?][br]
|
||||
[br]
|
||||
Handle has a single template parameter specifying the type of the managed object. This type is PyObject 99% of the time, so the parameter was defaulted to PyObject for convenience. Therefore we can use the shorthand handle<> instead of the longer, but equivalent, handle<PyObject>.
|
||||
]
|
||||
|
||||
When a ['borrowed] reference is returned, you do not have ownership of the reference. So if you just want to discard the return value, there is nothing you have to do: you didn't own it anyway. If want to use it however, you'll first have to increase its reference count (to prevent the object's deletion). Then later on when you are done with itm you'll need to decrease the reference count again. Here's another example:
|
||||
[h2 Running Python code]
|
||||
|
||||
// Retrieve the first item in the tuple
|
||||
PyObject* first = PyTuple_GetItem(my_tuple, 0);
|
||||
Py_XINCREF(first);
|
||||
... // Use first here
|
||||
// We're done with the first tuple item
|
||||
Py_XDECREF(first);
|
||||
|
||||
While this certainly works, it's hardly elegant and it's easy to make mistakes, especially when there are multiple execution paths.
|
||||
|
||||
[h2 Running Python code from C++]
|
||||
|
||||
To run Python code from C++ there is a family of functions in the API starting with the PyRun_ prefix. You can find the list of these fuctions [@http://www.python.org/doc/current/api/veryhigh.html here]. I shall discuss one of them, the others work very similarly.
|
||||
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 [@http://www.python.org/doc/current/api/veryhigh.html here]. They all work similarly so we will look at only one of them, namely:
|
||||
|
||||
PyObject* PyRun_String(char *str, int start, PyObject *globals, PyObject *locals)
|
||||
|
||||
PyRun_String takes the code to execute as a null-terminated (C-style) string in its [^str] parameter. The function returns a new reference to the Python object which results from executing the code. If a Python exception occurred during execution, the null pointer is returned.
|
||||
PyRun_String takes the code to execute as a null-terminated (C-style) string in its [^str] parameter. The function returns a new reference to a Python object. Which object is returned depends on the [^start] paramater.
|
||||
|
||||
The [^start] parameter is the start symbol from the Python grammar to use for interpreting the code. The possible values are:
|
||||
|
||||
@@ -92,83 +111,80 @@ The [^start] parameter is the start symbol from the Python grammar to use for in
|
||||
[Py_single_input] [for interpreting a single statement]
|
||||
]
|
||||
|
||||
Lastly, the [^globals] and [^locals] parameters are Python dictionaries containing the globals and locals of the context in which to run the code. For most intents and purposes you can use the namespace dictionary of the running module for both [^globals] and [^locals].
|
||||
When using Py_eval_input, the input string must contain a single expression and its result is returned. When using Py_file_input, the string can contain an abitrary number of statements and None is returned. Py_single_input works in the same way as Py_file_input but only accepts a single statement.
|
||||
|
||||
So how do we get a module's namespace dictionary? First we need to get a reference to the module. The function to do this is PyImport_AddModule. Contrary to what you might guess from its name, it returns a borrowed reference to an [*existing] module.
|
||||
Lastly, the [^globals] and [^locals] parameters are Python dictionaries containing the globals and locals of the context in which to run the code. For most intents and purposes you can use the namespace dictionary of the [^__main__] module for both parameters.
|
||||
|
||||
Then once we have a reference to the module, we can use PyModule_GetDict to get a borrowed reference to the module's namespace dictionary.
|
||||
We have already seen how to get the [^__main__] module's namespace so let's run some Python code in it:
|
||||
|
||||
Since the running module is usually the [^__main__] module created upon interpreter initialization, the code to execute a Python program from a string becomes:
|
||||
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()) );
|
||||
|
||||
// Get the __main__ module namespace
|
||||
PyObject* main_module = PyImport_AddModule("__main__");
|
||||
Py_XINCREF(main_module);
|
||||
PyObject* main_namespace = PyModule_GetDict(main_module);
|
||||
Py_XINCREF(main_namespace);
|
||||
// Run a single Python expression and retrieve the result
|
||||
PyObject* result = PyRun_String("1 + 1",
|
||||
Py_eval_input, main_namespace, main_namespace);
|
||||
... // Use the result
|
||||
// Cleanup
|
||||
Py_XDECREF(result);
|
||||
Py_XDECREF(main_namespace);
|
||||
Py_XDECREF(main_module);
|
||||
This should create a file called 'hello.txt' in the current directory containing a phrase that is well-known in programming circles.
|
||||
|
||||
__note__ [*Note] that we wrap the return value of PyRun_String in a (nameless) handle 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 PyObject pointers in handles.
|
||||
|
||||
[blurb __alert__ [*Warning][br][br]
|
||||
[h2 Beyond handles]
|
||||
|
||||
Be careful about what Python code you run and where. Running the addition above on your computer can hardly do any harm. But letting users run arbitrary Python code through your program which is running on a webserver can be a security risk.
|
||||
]
|
||||
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:
|
||||
|
||||
[:['[*Next up: How Boost.Python can simplify embedding...]]]
|
||||
handle<> main_module(borrowed( PyImport_AddModule("__main__") ));
|
||||
main_namespace dict(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"] );
|
||||
|
||||
[page:1 Embedding with Boost.Python]
|
||||
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:
|
||||
|
||||
[h2 Boost.Python to the rescue]
|
||||
object result(handle<>( PyRun_String("5 ** 2", Py_eval_input,
|
||||
main_namespace.ptr(), main_namespace.ptr()) ));
|
||||
int five_squared = extract<int>(result);
|
||||
|
||||
Now we get to the good news. If you don't want to do all the error prone reference counting yourself, you can let Boost.Python do all the work. First include [^<boost/python.hpp>] instead of [^"Python.h"] and link to [^boost_python.lib] (or [^boost_python_debug.lib]) instead of [^pythonXY.lib]. Then all we really need to do is replace every PyObject* with handle<> and we can remove all the Py_XINCREFs and Py_XDECREFs! All the reference counting will be done automagically through the power of the [@http://sourceforge.net/docman/display_doc.php?docid=8673&group_id=9028 Resource Acquisition Is Initialization] idiom.
|
||||
__note__ [*Note] that [^object]'s member function to return the wrapped PyObject pointer is called [^ptr] instead of [^get]. This makes sense if you take into account the different functions that object and handle perform.
|
||||
|
||||
We still need a way to differentiate between new and borrowed references though. Luckily, this is pretty straightforward using the [@../../v2/handle.html#borrowed-spec borrowed] function. Let's rewrite the example to run Python code from a string to use handles:
|
||||
[h2 Exception handling]
|
||||
|
||||
// Get the __main__ module namespace
|
||||
handle<> main_module( borrowed(PyImport_AddModule("__main__")) );
|
||||
handle<> main_namespace( borrowed(PyModule_GetDict(main_module)) );
|
||||
// Run a single Python expression and retrieve the result
|
||||
handle<> result( PyRun_String("1 + 1",
|
||||
Py_eval_input, main_namespace.get(), main_namespace.get()) );
|
||||
... // Use the result
|
||||
If an exception occurs in the execution of some Python code, the PyRun_String function returns a null pointer. Constructing a handle out of this null pointer throws [@../../v2/errors.html#error_already_set-spec error_already_set], so basically, the Python exception is automatically translated into a C++ exception when using handle:
|
||||
|
||||
The [@../../v2/handle.html#handle-spec-observers get]() member function used here returns the raw PyObject* that is held by the handle.
|
||||
|
||||
[h2 Boost.Python modules in an embedded program]
|
||||
|
||||
Now that we know how to call Python code from C++ and C++ code from Python, how about doing both at the same time? Sometimes you might want to call Python code from C++ and have that Python code call C++ code again.
|
||||
|
||||
If you built your Boost.Python module and put it in the proper directory, you can just use it in your embedded Python code as you would in a standalone Python program. The embedded interpreter will be able to find your module just as the standalone interpreter would.
|
||||
|
||||
However, you can also define the Boost.Python module in the same program that embeds the Python interpreter. Then you won't have to build the module seperately and place it in the proper directory. This also prevents others from using your module in their own Python code. (Unless they start taking your executable apart that is. :-))
|
||||
|
||||
Doing this is relatively straightforward. You just define your Boost.Python module as usual and use the basic embedding steps described earlier. However, before calling Py_Initialize you call PyImport_AppendInittab first.
|
||||
|
||||
This function takes the name and [@../../v2/module.html#BOOST_PYTHON_MODULE-spec initialization function] of your module as parameters and adds the module to the interpreter's list of builtin modules. So when the Python interpreter comes across an import statement, it will find the module in its list of builtin modules instead of (unsuccessfully) searching for it in the Python directory.
|
||||
|
||||
Your program will look something like this:
|
||||
|
||||
BOOST_PYTHON_MODULE(my_module)
|
||||
try
|
||||
{
|
||||
...
|
||||
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);
|
||||
}
|
||||
catch(error_already_set)
|
||||
{
|
||||
// handle the exception in some way
|
||||
}
|
||||
...
|
||||
PyImport_AppendInittab("my_module", initmy_module);
|
||||
Py_Initialize();
|
||||
...
|
||||
|
||||
[blurb __alert__ [*Warning][br][br]
|
||||
The [^error_already_set] exception class doesn't carry any information in itself. To find out more about the Python exception that occurred, you need to use the [@http://www.python.org/doc/api/exceptionHandling.html exception handling functions] of the Python/C API in your catch-statement. This can be as simple as calling PyErr_Print() to print the exception's traceback to the console, or comparing the type of the exception with those of the [@http://www.python.org/doc/api/standardExceptions.html standard exceptions]:
|
||||
|
||||
When creating Boost.Python modules in the same program that embeds interpreter, you must [*['not]] call Py_Finalize. Boost.Python keeps some PyObject references alive in global data structures, and when those go out of scope after interpreter finalization, Python crashes. This will be fixed in the future. Stay tuned.
|
||||
]
|
||||
catch(error_already_set)
|
||||
{
|
||||
if (PyErr_ExceptionMatches(PyExc_ZeroDivisionError))
|
||||
{
|
||||
// handle ZeroDivisionError specially
|
||||
}
|
||||
else
|
||||
{
|
||||
// print all other errors to stderr
|
||||
PyErr_Print();
|
||||
}
|
||||
}
|
||||
|
||||
[h2 Additional reading]
|
||||
(To retrieve even more information from the exception you can use some of the other exception handling functions listed [@http://www.python.org/doc/api/exceptionHandling.html here].)
|
||||
|
||||
A more elaborate example showing these techniques is located at [@../../../test/embedding.cpp /libs/python/test/embedding.cpp].
|
||||
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()) ));
|
||||
if (!result)
|
||||
// Python exception occurred
|
||||
else
|
||||
// everything went okay, it's safe to use the result
|
||||
|
||||
|
||||
183
doc/tutorial/doc/using_the_interpreter.html
Normal file
183
doc/tutorial/doc/using_the_interpreter.html
Normal file
@@ -0,0 +1,183 @@
|
||||
<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">
|
||||
</head>
|
||||
<body>
|
||||
<table width="100%" height="48" border="0" background="theme/bkd2.gif" cellspacing="2">
|
||||
<tr>
|
||||
<td width="10">
|
||||
</td>
|
||||
<td width="85%">
|
||||
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Using the interpreter</b></font>
|
||||
</td>
|
||||
<td width="112"><a href="http://spirit.sf.net"><img src="theme/spirit.gif" align="right" border="0"></a></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"><img src="theme/r_arr_disabled.gif" border="0"></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
As you probably already know, objects in Python are reference-counted. Naturally, the PyObjects 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 PyObject*: 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 handle that the PyObject pointer 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=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=special>));
|
||||
</span></pre></code>
|
||||
<p>
|
||||
Because the Python/C API doesn't know anything about handles, we used the <a href="../../v2/handle.html#handle-spec-observers">
|
||||
get</a> member function to retrieve the PyObject pointer from which the handle was constructed.</p>
|
||||
<p>
|
||||
For a function returning a <i>new reference</i> we can just create a handle out of the raw PyObject pointer 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>
|
||||
Handle has a single template parameter specifying the type of the managed object. This type is PyObject 99% of the time, so the parameter was defaulted to PyObject for convenience. Therefore we can use the shorthand handle<> instead of the longer, but equivalent, handle<PyObject>.
|
||||
</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=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=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><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) handle 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 PyObject pointers in handles.</p>
|
||||
<a name="beyond_handles"></a><h2>Beyond handles</h2><p>
|
||||
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 <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 handle. 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=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=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=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><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=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 PyObject pointer is called <tt>ptr</tt> instead of <tt>get</tt>. This makes sense if you take into account the different functions that object and handle 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 handle 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 handle:</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=special>));
|
||||
</span><span class=comment>// execution will never get here:
|
||||
</span><span class=keyword>int </span><span class=identifier>five_divided_by_zero </span><span class=special>= </span><span class=identifier>extract</span><span class=special><</span><span class=keyword>int</span><span class=special>>(</span><span class=identifier>result</span><span class=special>);
|
||||
</span><span class=special>}
|
||||
</span><span class=keyword>catch</span><span class=special>(</span><span class=identifier>error_already_set</span><span class=special>)
|
||||
</span><span class=special>{
|
||||
</span><span class=comment>// handle the exception in some 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 PyErr_Print() 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=special>{
|
||||
</span><span class=keyword>if </span><span class=special>(</span><span class=identifier>PyErr_ExceptionMatches</span><span class=special>(</span><span class=identifier>PyExc_ZeroDivisionError</span><span class=special>))
|
||||
</span><span class=special>{
|
||||
</span><span class=comment>// handle ZeroDivisionError specially
|
||||
</span><span class=special>}
|
||||
</span><span class=keyword>else
|
||||
</span><span class=special>{
|
||||
</span><span class=comment>// print all other errors to stderr
|
||||
</span><span class=identifier>PyErr_Print</span><span class=special>();
|
||||
</span><span class=special>}
|
||||
</span><span class=special>}
|
||||
</span></pre></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 handle 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=special>));
|
||||
</span><span class=keyword>if </span><span class=special>(!</span><span class=identifier>result</span><span class=special>)
|
||||
</span><span class=comment>// Python exception occurred
|
||||
</span><span class=keyword>else
|
||||
</span><span class=comment>// everything went okay, it's safe to use the result
|
||||
</span></pre></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"><img src="theme/r_arr_disabled.gif" border="0"></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>
|
||||
Reference in New Issue
Block a user