diff --git a/doc/tutorial/doc/html/index.html b/doc/tutorial/doc/html/index.html index d8be7da8..8a1e5410 100644 --- a/doc/tutorial/doc/html/index.html +++ b/doc/tutorial/doc/html/index.html @@ -30,7 +30,7 @@
-

+

Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at @@ -52,7 +52,6 @@

Class Properties
Inheritance
Class Virtual Functions
-
Deriving a Python Class
Virtual Functions with Default Implementations
Class Operators/Special Functions
@@ -97,7 +96,7 @@ metaprogramming techniques simplifies its syntax for users, so that wrapping code takes on the look of a kind of declarative interface definition language (IDL).

-Hello World

+Hello World

Following C/C++ tradition, let's start with the "hello, world". A C++ Function:

@@ -124,7 +123,7 @@ hello, world
- +

Last revised: October 30, 2004 at 10:39:27 GMT

Last revised: October 12, 2004 at 03:11:11 GMT


diff --git a/doc/tutorial/doc/html/python/object.html b/doc/tutorial/doc/html/python/object.html index c842c3f1..25092680 100644 --- a/doc/tutorial/doc/html/python/object.html +++ b/doc/tutorial/doc/html/python/object.html @@ -42,7 +42,7 @@ As mentioned, one of the goals of Boost.Python is to provide a bidirectional mapping between C++ and Python while maintaining the Python feel. Boost.Python C++ objects are as close as possible to Python. This should minimize the learning curve significantly.

-

+

Basic Interface

diff --git a/doc/tutorial/doc/tutorial.qbk b/doc/tutorial/doc/tutorial.qbk index bc622480..a6ca4eb8 100644 --- a/doc/tutorial/doc/tutorial.qbk +++ b/doc/tutorial/doc/tutorial.qbk @@ -111,7 +111,7 @@ minimalist ['bjam] script that builds the DLLs for us. Before anything else, you should have the bjam executable in your boost directory or somewhere in your path such that [^bjam] can be executed in the command line. Pre-built Boost.Jam executables are available for most -platforms. The complete list of Bjam executables can be found +platforms. The complete list of Bjam executables can be found [@http://sourceforge.net/project/showfiles.php?group_id=7586 here]. [h2 Let's Jam!] @@ -175,7 +175,7 @@ Python modules. Example: The above assumes that the Python installation is in [^c:/dev/tools/python] and that we are using Python version 2.2. You'll have to tweak this path -appropriately. +appropriately. [blurb __tip__ Be sure not to include a third number, e.g. [*not] "2.2.1", even if that's the version you have.] @@ -454,8 +454,11 @@ Now we can inform Boost.Python of the inheritance relationship between Doing so, we get some things for free: -# Derived automatically inherits all of Base's Python methods (wrapped C++ member functions) -# [*If] Base is polymorphic, [^Derived] objects which have been passed to Python via a pointer or reference to [^Base] can be passed where a pointer or reference to [^Derived] is expected. +# Derived automatically inherits all of Base's Python methods + (wrapped C++ member functions) +# [*If] Base is polymorphic, [^Derived] objects which have been passed to + Python via a pointer or reference to [^Base] can be passed where a pointer + or reference to [^Derived] is expected. Now, we shall expose the C++ free functions [^b] and [^d] and [^factory]: @@ -475,148 +478,73 @@ Boost.Python [link python.call_policies call policies] later. return_value_policy()); [endsect] + [section Class Virtual Functions] -In this section, we shall learn how to make functions behave -polymorphically through virtual functions. Continuing our example, let us -add a virtual function to our [^Base] class: +In this section, we shall learn how to make functions behave polymorphically +through virtual functions. Continuing our example, let us add a virtual function +to our [^Base] class: struct Base { + virtual ~Base() {} virtual int f() = 0; }; -Since [^f] is a pure virtual function, [^Base] is now an abstract -class. Given an instance of our class, the free function [^call_f] -calls some implementation of this virtual function in a concrete -derived class: +One of the goals of Boost.Python is to be minimally intrusive on an existing C++ +design. In principle, it should be possible to expose the interface for a 3rd +party library without changing it. It is not ideal to add anything to our class +`Base`. Yet, when you have a virtual function that's going to be overridden in +Python and called polymorphically *from C++*, we'll need to add some +scaffoldings to make things work properly. What we'll do is write a class +wrapper that derives from `Base` that will unintrusively hook into the virtual +functions so that a Python override may be called: - int call_f(Base& b) { return b.f(); } - -To allow this function to be implemented in a Python derived class, we -need to create a class wrapper: - - struct BaseWrap : Base + struct BaseWrap : Base, wrapper { - BaseWrap(PyObject* self_) - : self(self_) {} - int f() { return call_method(self, "f"); } - PyObject* self; + int f() + { + return this->get_override("f")(); + } }; +Notice too that in addition to inheriting from `Base`, we also multiply- +inherited `wrapper` (See [@../../../v2//wrapper.html Wrapper]). The +`wrapper` template makes the job of wrapping classes that are meant to +overridden in Python, easier. - struct BaseWrap : Base - { - BaseWrap(PyObject* self_) - : self(self_) {} - BaseWrap(PyObject* self_, Base const& copy) - : Base(copy), self(self_) {} - int f() { return call_method(self, "f"); } - int default_f() { return Base::f(); } // <<=== ***ADDED*** - PyObject* self; - }; +[blurb __alert__ MSVC6/7 Workaround\n\n +If you are using Microsoft Visual C++ 6 or 7, you have to write `f` as:\n\n +`return call(this->get_override("f").ptr());`.] + +BaseWrap's overridden virtual member function `f` in effect calls the +corresponding method of the Python object through `get_override`. + +Finally, exposing `Base`: + + class_("Base") + .def("f", pure_virtual(&Base::f)) + ; + +`pure_virtual` signals Boost.Python that the function `f` is a pure virtual +function. [blurb __note__ [*member function and methods]\n\n Python, like many object oriented languages uses the term [*methods]. Methods correspond roughly to C++'s [*member functions]] -Our class wrapper [^BaseWrap] is derived from [^Base]. Its overridden -virtual member function [^f] in effect calls the corresponding method -of the Python object [^self], which is a pointer back to the Python -[^Base] object holding our [^BaseWrap] instance. - -[blurb __note__ [*Why do we need BaseWrap?]\n\n] - -['You may ask], "Why do we need the [^BaseWrap] derived class? This could -have been designed so that everything gets done right inside of -Base."\n\n - -One of the goals of Boost.Python is to be minimally intrusive on an -existing C++ design. In principle, it should be possible to expose the -interface for a 3rd party library without changing it. To unintrusively -hook into the virtual functions so that a Python override may be called, we -must use a derived class.\n\n - -Note however that you don't need to do this to get methods overridden -in Python to behave virtually when called ['from] [*Python]. The only -time you need to do the [^BaseWrap] dance is when you have a virtual -function that's going to be overridden in Python and called -polymorphically ['from] [*C++].] - -Wrapping [^Base] and the free function [^call_f]: - - class_("Base", no_init) - ; - def("call_f", call_f); - -Notice that we parameterized the [^class_] template with [^BaseWrap] as the -second parameter. What is [^noncopyable]? Without it, the library will try -to create code for converting Base return values of wrapped functions to -Python. To do that, it needs Base's copy constructor... which isn't -available, since Base is an abstract class. - -In Python, let us try to instantiate our [^Base] class: - - >>> base = Base() - RuntimeError: This class cannot be instantiated from Python - -Why is it an error? [^Base] is an abstract class. As such it is advisable -to define the Python wrapper with [^no_init] as we have done above. Doing -so will disallow abstract base classes such as [^Base] to be instantiated. - [endsect] -[section Deriving a Python Class] -Continuing, we can derive from our base class Base in Python and override -the virtual function in Python. Before we can do that, we have to set up -our [^class_] wrapper as: - - class_("Base") - ; - -Otherwise, we have to suppress the Base class' [^no_init] by adding an -[^__init__()] method to all our derived classes. [^no_init] actually adds -an [^__init__] method that raises a Python RuntimeError exception. - - >>> class Derived(Base): - ... def f(self): - ... return 42 - ... - -Cool eh? A Python class deriving from a C++ class! - -Let's now make an instance of our Python class [^Derived]: - - >>> derived = Derived() - -Calling [^derived.f()]: - - >>> derived.f() - 42 - -Will yield the expected result. Finally, calling calling the free function -[^call_f] with [^derived] as argument: - - >>> call_f(derived) - 42 - -Will also yield the expected result. - -Here's what's happening: - -# [^call_f(derived)] is called in Python -# This corresponds to [^def("call_f", call_f);]. Boost.Python dispatches this call. -# [^int call_f(Base& b) { return b.f(); }] accepts the call. -# The overridden virtual function [^f] of [^BaseWrap] is called. -# [^call_method(self, "f");] dispatches the call back to Python. -# [^def f(self): return 42] is finally called. - -[endsect] [section Virtual Functions with Default Implementations] -Recall that in the [link python.class_virtual_functions previous section], we -wrapped a class with a pure virtual function that we then implemented in -C++ or Python classes derived from it. Our base class: +We've seen in the previous section how classes with pure virtual functions are +wrapped using Boost.Python's [@../../../v2//wrapper.html class wrapper] +facilities. If we wish to wrap [*non]-pure-virtual functions instead, the +mechanism is a bit different. + +Recall that in the [link python.class_virtual_functions previous section], we +wrapped a class with a pure virtual function that we then implemented in C++, or +Python classes derived from it. Our base class: struct Base { @@ -628,33 +556,42 @@ not declared as pure virtual: struct Base { + virtual ~Base() {} virtual int f() { return 0; } }; -and instead had a default implementation that returns [^0], as shown above, -we need to add a forwarding function that calls the [^Base] default virtual -function [^f] implementation: - - struct BaseWrap : Base +We wrap it this way: + + struct BaseWrap : Base, wrapper { - BaseWrap(PyObject* self_) - : self(self_) {} - int f() { return call_method(self, "f"); } - int default_f() { return Base::f(); } // <<=== ***ADDED*** - PyObject* self; + int f() + { + if (override f = this->get_override("f")) + return f(); // *note* + return Base::f(); + } + + int default_f() { return this->Base::f(); } }; + +Notice how we implemented `BaseWrap::f`. Now, we have to check if there is an +override for `f`. If none, then we call `Base::f()`. -Then, Boost.Python needs to keep track of 1) the dispatch function [^f] and -2) the forwarding function to its default implementation [^default_f]. -There's a special [^def] function for this purpose. Here's how it is -applied to our example above: +[blurb __alert__ MSVC6/7 Workaround\n\n +If you are using Microsoft Visual C++ 6 or 7, you have to rewrite the line +with the `*note*` as:\n\n +`return call(f.ptr());`.] - class_("Base") +Finally, exposing: + + class_("Base") .def("f", &Base::f, &BaseWrap::default_f) + ; -Note that we are allowing [^Base] objects to be instantiated this time, -unlike before where we specifically defined the [^class_] with -[^no_init]. +Take note that we expose both `&Base::f` and `&BaseWrap::default_f`. +Boost.Python needs to keep track of 1) the dispatch function [^f] and 2) the +forwarding function to its default implementation [^default_f]. There's a +special [^def] function for this purpose. In Python, the results would be as expected: @@ -675,16 +612,6 @@ Calling [^derived.f()]: >>> derived.f() 42 -Calling [^call_f], passing in a [^base] object: - - >>> call_f(base) - 0 - -Calling [^call_f], passing in a [^derived] object: - - >>> call_f(derived) - 42 - [endsect] [section Class Operators/Special Functions] @@ -1179,7 +1106,7 @@ bidirectional mapping between C++ and Python while maintaining the Python feel. Boost.Python C++ [^object]s are as close as possible to Python. This should minimize the learning curve significantly. -[$../images/python.png] +[$images/python.png] [section Basic Interface] @@ -1422,7 +1349,7 @@ 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 +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 @@ -1622,10 +1549,10 @@ 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 +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 @@ -1645,13 +1572,13 @@ C++ exception when using [^handle]: // 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 +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) @@ -1667,11 +1594,11 @@ standard exceptions]: } } -(To retrieve even more information from the exception you can use some of the other +(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 +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( @@ -1859,7 +1786,7 @@ actually a Python package. It can be a empty file, but can also perform some magic, that will be shown later. Now our package is ready. All the user has to do is put [^sounds] into his -[@http://www.python.org/doc/current/tut/node8.html#SECTION008110000000000000000 PYTHONPATH] +[@http://www.python.org/doc/current/tut/node8.html#SECTION008110000000000000000 PYTHONPATH] and fire up the interpreter: >>> import sounds.io @@ -1980,7 +1907,7 @@ we have a class [^point] in C++: } If we are using the technique from the previous session, -[link python.creating_packages Creating Packages], we can code directly +[link python.creating_packages Creating Packages], we can code directly into [^geom/__init__.py]: from _geom import * diff --git a/doc/tutorial/doc/tutorial.xml b/doc/tutorial/doc/tutorial.xml index 1a9c1c5f..21ad2876 100644 --- a/doc/tutorial/doc/tutorial.xml +++ b/doc/tutorial/doc/tutorial.xml @@ -162,10 +162,10 @@ minimalist bjam script that builds the DLLs for us. Before anything else, you should have the bjam executable in your boost directory or somewhere in your path such that bjam can be executed in the command line. Pre-built Boost.Jam executables are available for most -platforms. The complete list of Bjam executables can be found +platforms. The complete list of Bjam executables can be found here. Let's Jam! - + Here is our minimalist Jamfile: subproject libs/python/example/tutorial ; @@ -563,9 +563,12 @@ Now we can inform Boost.Python of the inheritance relationship between Doing so, we get some things for free: -Derived automatically inherits all of Base's Python methods (wrapped C++ member functions) +Derived automatically inherits all of Base's Python methods + (wrapped C++ member functions) -If Base is polymorphic, Derived objects which have been passed to Python via a pointer or reference to Base can be passed where a pointer or reference to Derived is expected. +If Base is polymorphic, Derived objects which have been passed to + Python via a pointer or reference to Base can be passed where a pointer + or reference to Derived is expected. Now, we shall expose the C++ free functions b and d and factory: @@ -594,53 +597,75 @@ Boost.Python call policies later.

Class Virtual Functions -In this section, we shall learn how to make functions behave -polymorphically through virtual functions. Continuing our example, let us -add a virtual function to our Base class: +In this section, we shall learn how to make functions behave polymorphically +through virtual functions. Continuing our example, let us add a virtual function +to our Base class: struct Base { + virtual ~Base() {} virtual int f() = 0; }; -Since f is a pure virtual function, Base is now an abstract -class. Given an instance of our class, the free function call_f -calls some implementation of this virtual function in a concrete -derived class: +One of the goals of Boost.Python is to be minimally intrusive on an existing C++ +design. In principle, it should be possible to expose the interface for a 3rd +party library without changing it. It is not ideal to add anything to our class +Base. Yet, when you have a virtual function that's going to be overridden in +Python and called polymorphically from C++, we'll need to add some +scaffoldings to make things work properly. What we'll do is write a class +wrapper that derives from Base that will unintrusively hook into the virtual +functions so that a Python override may be called: -int call_f(Base& b) { return b.f(); } - - - -To allow this function to be implemented in a Python derived class, we -need to create a class wrapper: - - -struct BaseWrap : Base -{ - BaseWrap(PyObject* self_) - : self(self_) {} - int f() { return call_method<int>(self, "f"); } - PyObject* self; -}; - - -struct BaseWrap : Base -{ - BaseWrap(PyObject* self_) - : self(self_) {} - BaseWrap(PyObject* self_, Base const& copy) - : Base(copy), self(self_) {} - int f() { return call_method<int>(self, "f"); } - int default_f() { return Base::f(); } // <<=== ***ADDED*** - PyObject* self; +struct BaseWrap : Base, wrapper<Base> +{ + int f() + { + return this->get_override("f")(); + } }; + +Notice too that in addition to inheriting from Base, we also multiply- +inherited wrapper<Base> (See Wrapper). The +wrapper template makes the job of wrapping classes that are meant to +overridden in Python, easier. + + + + + + + MSVC6/7 Workaround + + +If you are using Microsoft Visual C++ 6 or 7, you have to write f as: + + +return call<int>(this->get_override("f").ptr());. + + + + + +BaseWrap's overridden virtual member function f in effect calls the +corresponding method of the Python object through get_override. + +Finally, exposing Base: + + +class_<BaseWrap, boost::noncopyable>("Base") + .def("f", pure_virtual(&Base::f)) + ; + + + +pure_virtual signals Boost.Python that the function f is a pure virtual +function. @@ -656,147 +681,18 @@ correspond roughly to C++'s member functions - -Our class wrapper BaseWrap is derived from Base. Its overridden -virtual member function f in effect calls the corresponding method -of the Python object self, which is a pointer back to the Python -Base object holding our BaseWrap instance. - - - - - - - Why do we need BaseWrap? - - - - - - - -You may ask, "Why do we need the BaseWrap derived class? This could -have been designed so that everything gets done right inside of -Base." - - - -One of the goals of Boost.Python is to be minimally intrusive on an -existing C++ design. In principle, it should be possible to expose the -interface for a 3rd party library without changing it. To unintrusively -hook into the virtual functions so that a Python override may be called, we -must use a derived class. - - - -Note however that you don't need to do this to get methods overridden -in Python to behave virtually when called from Python. The only -time you need to do the BaseWrap dance is when you have a virtual -function that's going to be overridden in Python and called -polymorphically from C++.] - -Wrapping Base and the free function call_f: - - -class_<Base, BaseWrap, boost::noncopyable>("Base", no_init) - ; -def("call_f", call_f); - - - -Notice that we parameterized the class_ template with BaseWrap as the -second parameter. What is noncopyable? Without it, the library will try -to create code for converting Base return values of wrapped functions to -Python. To do that, it needs Base's copy constructor... which isn't -available, since Base is an abstract class. - -In Python, let us try to instantiate our Base class: - - ->>> base = Base() -RuntimeError: This class cannot be instantiated from Python - - - -Why is it an error? Base is an abstract class. As such it is advisable -to define the Python wrapper with no_init as we have done above. Doing -so will disallow abstract base classes such as Base to be instantiated. -
-Deriving a Python Class - -Continuing, we can derive from our base class Base in Python and override -the virtual function in Python. Before we can do that, we have to set up -our class_ wrapper as: - - -class_<Base, BaseWrap, boost::noncopyable>("Base") - ; - - - -Otherwise, we have to suppress the Base class' no_init by adding an -_init_() method to all our derived classes. no_init actually adds -an _init_ method that raises a Python RuntimeError exception. - - ->>> class Derived(Base): -... def f(self): -... return 42 -... - - - -Cool eh? A Python class deriving from a C++ class! - -Let's now make an instance of our Python class Derived: - - ->>> derived = Derived() - - - -Calling derived.f(): - - ->>> derived.f() -42 - - - -Will yield the expected result. Finally, calling calling the free function -call_f with derived as argument: - - ->>> call_f(derived) -42 - - - -Will also yield the expected result. - -Here's what's happening: - - -call_f(derived) is called in Python - -This corresponds to def("call_f", call_f);. Boost.Python dispatches this call. - -int call_f(Base& b) { return b.f(); } accepts the call. - -The overridden virtual function f of BaseWrap is called. - -call_method<int>(self, "f"); dispatches the call back to Python. - -def f(self): return 42 is finally called. - -
Virtual Functions with Default Implementations -Recall that in the previous section, we -wrapped a class with a pure virtual function that we then implemented in -C++ or Python classes derived from it. Our base class: +We've seen in the previous section how classes with pure virtual functions are +wrapped using Boost.Python's class wrapper +facilities. If we wish to wrap non-pure-virtual functions instead, the +mechanism is a bit different. + +Recall that in the previous section, we +wrapped a class with a pure virtual function that we then implemented in C++, or +Python classes derived from it. Our base class: struct Base @@ -812,41 +708,63 @@ not declared as pure virtual: struct Base { + virtual ~Base() {} virtual int f() { return 0; } }; -and instead had a default implementation that returns 0, as shown above, -we need to add a forwarding function that calls the Base default virtual -function f implementation: +We wrap it this way: -struct BaseWrap : Base -{ - BaseWrap(PyObject* self_) - : self(self_) {} - int f() { return call_method<int>(self, "f"); } - int default_f() { return Base::f(); } // <<=== ***ADDED*** - PyObject* self; +struct BaseWrap : Base, wrapper<Base> +{ + int f() + { + if (override f = this->get_override("f")) + return f(); // *note* + return Base::f(); + } + + int default_f() { return this->Base::f(); } }; -Then, Boost.Python needs to keep track of 1) the dispatch function f and -2) the forwarding function to its default implementation default_f. -There's a special def function for this purpose. Here's how it is -applied to our example above: +Notice how we implemented BaseWrap::f. Now, we have to check if there is an +override for f. If none, then we call Base::f(). + + + + + + + MSVC6/7 Workaround + + +If you are using Microsoft Visual C++ 6 or 7, you have to rewrite the line +with the *note* as: + + +return call<char const*>(f.ptr());. + + + + + +Finally, exposing: -class_<Base, BaseWrap, BaseWrap, boost::noncopyable>("Base") - .def("f", &Base::f, &BaseWrap::default_f) +class_<BaseWrap, boost::noncopyable>("Base") + .def("f", &Base::f, &BaseWrap::default_f) + ; -Note that we are allowing Base objects to be instantiated this time, -unlike before where we specifically defined the class_<Base> with -no_init. +Take note that we expose both &Base::f and &BaseWrap::default_f. +Boost.Python needs to keep track of 1) the dispatch function f and 2) the +forwarding function to its default implementation default_f. There's a +special def function for this purpose. In Python, the results would be as expected: @@ -875,22 +793,6 @@ Calling derived.f(): 42 - -Calling call_f, passing in a base object: - - ->>> call_f(base) -0 - - - -Calling call_f, passing in a derived object: - - ->>> call_f(derived) -42 - -
Class Operators/Special Functions @@ -1823,7 +1725,7 @@ 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 +you probably haven't built Boost.Python yet. See Building and Testing on how to do this. Python's static link library can be found in the /libs subdirectory of @@ -2001,7 +1903,7 @@ you want to be a Dr. Frankenstein, always wrap PyObject*s in 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 -above, and in the previous section: the aptly +above, and in the 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: @@ -2047,10 +1949,10 @@ int five_squaredException 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 error_already_set, -so basically, the Python exception is automatically translated into a +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 error_already_set, +so basically, the Python exception is automatically translated into a C++ exception when using handle: @@ -2073,14 +1975,14 @@ catch(error_a -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 -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 -standard exceptions: +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 +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 exceptions: catch(error_already_set) @@ -2098,11 +2000,11 @@ standard exceptions: -(To retrieve even more information from the exception you can use some of the other +(To retrieve even more information from the exception you can use some of the other exception handling functions listed here.) -If you'd rather not have handle throw a C++ exception when it is constructed, you -can use the allow_null function in the same +If you'd rather not have handle throw a C++ exception when it is constructed, you +can use the allow_null function in the same way you'd use borrowed: @@ -2345,7 +2247,7 @@ actually a Python package. It can be a empty file, but can also perform some magic, that will be shown later. Now our package is ready. All the user has to do is put sounds into his -PYTHONPATH +PYTHONPATH and fire up the interpreter: @@ -2493,7 +2395,7 @@ BOOST_PYTHON_MODULE(Creating Packages, we can code directly +Creating Packages, we can code directly into geom/_init_.py: