From 936c1118bdcab9f9f9def4f99feedf0c962a0eb4 Mon Sep 17 00:00:00 2001 From: Joel de Guzman Date: Wed, 19 Mar 2003 23:33:19 +0000 Subject: [PATCH] Bump to v1.6.0 [SVN r18021] --- doc/tutorial/doc/quickstart.txt | 252 ++++++++++++++++++++++++++++++++ 1 file changed, 252 insertions(+) diff --git a/doc/tutorial/doc/quickstart.txt b/doc/tutorial/doc/quickstart.txt index 7efc63bf..4dda6354 100644 --- a/doc/tutorial/doc/quickstart.txt +++ b/doc/tutorial/doc/quickstart.txt @@ -1330,6 +1330,258 @@ create a new scope around a class: .value("blue", blue) ; +[def Py_Initialize [@http://www.python.org/doc/current/api/initialization.html#l2h-652 Py_Initialize]] +[def Py_Finalize [@http://www.python.org/doc/current/api/initialization.html#l2h-656 Py_Finalize]] +[def PyRun_String [@http://www.python.org/doc/current/api/veryhigh.html#l2h-55 PyRun_String]] +[def PyRun_File [@http://www.python.org/doc/current/api/veryhigh.html#l2h-56 PyRun_File]] +[def Py_eval_input [@http://www.python.org/doc/current/api/veryhigh.html#l2h-58 Py_eval_input]] +[def Py_file_input [@http://www.python.org/doc/current/api/veryhigh.html#l2h-59 Py_file_input]] +[def Py_single_input [@http://www.python.org/doc/current/api/veryhigh.html#l2h-60 Py_single_input]] +[def Py_XINCREF [@http://www.python.org/doc/current/api/countingRefs.html#l2h-65 Py_XINCREF]] +[def Py_XDECREF [@http://www.python.org/doc/current/api/countingRefs.html#l2h-67 Py_XDECREF]] +[def PyImport_AppendInittab [@http://www.python.org/doc/current/api/importing.html#l2h-137 PyImport_AppendInittab]] +[def PyImport_AddModule [@http://www.python.org/doc/current/api/importing.html#l2h-125 PyImport_AddModule]] +[def PyModule_New [@http://www.python.org/doc/current/api/moduleObjects.html#l2h-591 PyModule_New]] +[def PyModule_GetDict [@http://www.python.org/doc/current/api/moduleObjects.html#l2h-594 PyModule_GetDict]] + +[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 + boost_python c:\boost\libs\python + $(PYTHON_PROPERTIES) + $(PYTHON_LIB_PATH) + $(PYTHON_EMBEDDED_LIBRARY) ; +] + +[h2 Getting started] + +Being able to build is nice, but there is nothing to build yet. Embedding +the Python interpreter into one of your C++ programs requires these 4 +steps: + +# '''#include''' [^][br][br] + +# Call Py_Initialize() to start the interpreter and create the [^__main__] module.[br][br] + +# Call other Python C API routines to use the interpreter.[br][br] + +# Call Py_Finalize() to stop the interpreter and release its resources. + +(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 Using the interpreter] + +As you probably already know, objects in Python are reference-counted. +Naturally, the [^PyObject]s of the Python/C API are also reference-counted. +There is a difference however. While the reference-counting is fully +automatic in Python, the Python/C API requires you to do it +[@http://www.python.org/doc/current/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. + +[h2 Reference-counting handles] + +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. + +For a function returning a ['borrowed reference] we'll have to tell the +[^handle] that the [^PyObject*] 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: + + handle<> main_module(borrowed( PyImport_AddModule("__main__") )); + handle<> main_namespace(borrowed( PyModule_GetDict(main_module.get()) )); + +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 +such function that returns a new reference is PyRun_String which we'll +discuss in the next section. + +[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]. +] + +[h2 Running Python code] + +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 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: + +[table Start symbols + + [Py_eval_input] [for interpreting isolated expressions] + [Py_file_input] [for interpreting sequences of statements] + [Py_single_input] [for interpreting a single statement] +] + +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. + +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. + +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()) ); + +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*]s in [^handle]s. + +[h2 Beyond handles] + +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: + + 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( 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()) )); + int five_squared = extract(result); + +__note__ [*Note] that [^object]'s member function to return the wrapped +[^PyObject*] is called [^ptr] instead of [^get]. This makes sense if you +take into account the different functions that [^object] and [^handle] +perform. + +[h2 Exception handling] + +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]: + + 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(result); + } + catch(error_already_set) + { + // handle the exception in some way + } + +The [^error_already_set] exception class doesn't carry any information in itself. To find out more about the Python exception that occurred, you need to use the [@http://www.python.org/doc/api/exceptionHandling.html exception handling functions] of the Python/C API in your catch-statement. This can be as simple as calling [@http://www.python.org/doc/api/exceptionHandling.html#l2h-70 PyErr_Print()] to print the exception's traceback to the console, or comparing the type of the exception with those of the [@http://www.python.org/doc/api/standardExceptions.html standard exceptions]: + + catch(error_already_set) + { + if (PyErr_ExceptionMatches(PyExc_ZeroDivisionError)) + { + // handle ZeroDivisionError specially + } + else + { + // print all other errors to stderr + PyErr_Print(); + } + } + +(To retrieve even more information from the exception you can use some of the other exception handling functions listed [@http://www.python.org/doc/api/exceptionHandling.html here].) + +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 + [page Iterators] In C++, and STL in particular, we see iterators everywhere. Python also has