From c4b09c7526c0619dd5b5dd4e83182ec2ce5295b3 Mon Sep 17 00:00:00 2001 From: Joel de Guzman Date: Thu, 16 Sep 2004 05:51:33 +0000 Subject: [PATCH] move to quickbook (WIP) [SVN r25137] --- doc/tutorial/doc/auto_overloading.html | 112 - doc/tutorial/doc/basic_interface.html | 77 - doc/tutorial/doc/building_hello_world.html | 196 -- doc/tutorial/doc/call_policies.html | 169 -- doc/tutorial/doc/class_data_members.html | 78 - .../class_operators_special_functions.html | 109 - doc/tutorial/doc/class_properties.html | 81 - doc/tutorial/doc/class_virtual_functions.html | 141 -- doc/tutorial/doc/constructors.html | 102 - doc/tutorial/doc/creating_packages.html | 210 -- doc/tutorial/doc/default_arguments.html | 158 -- doc/tutorial/doc/derived_object_types.html | 117 - doc/tutorial/doc/deriving_a_python_class.html | 83 - doc/tutorial/doc/embedding.html | 97 - doc/tutorial/doc/enums.html | 95 - doc/tutorial/doc/exception_translation.html | 61 - doc/tutorial/doc/exposing_classes.html | 79 - .../extending_wrapped_objects_in_python.html | 134 -- doc/tutorial/doc/extracting_c___objects.html | 79 - doc/tutorial/doc/functions.html | 73 - doc/tutorial/doc/general_techniques.html | 43 - doc/tutorial/doc/inheritance.html | 98 - doc/tutorial/doc/iterators.html | 101 - doc/tutorial/doc/object_interface.html | 54 - doc/tutorial/doc/overloading.html | 88 - doc/tutorial/doc/quickstart.html | 79 - doc/tutorial/doc/quickstart.txt | 2047 ----------------- doc/tutorial/doc/reducing_compiling_time.html | 115 - doc/tutorial/doc/theme/Thumbs.db | Bin 27136 -> 0 bytes doc/tutorial/doc/theme/alert.gif | Bin 577 -> 0 bytes doc/tutorial/doc/theme/arrow.gif | Bin 70 -> 0 bytes doc/tutorial/doc/theme/bkd.gif | Bin 1317 -> 0 bytes doc/tutorial/doc/theme/bkd2.gif | Bin 2543 -> 0 bytes doc/tutorial/doc/theme/bulb.gif | Bin 944 -> 0 bytes doc/tutorial/doc/theme/bullet.gif | Bin 152 -> 0 bytes doc/tutorial/doc/theme/c++boost.gif | Bin 8819 -> 0 bytes doc/tutorial/doc/theme/jam.png | Bin 3884 -> 0 bytes doc/tutorial/doc/theme/l_arr.gif | Bin 147 -> 0 bytes doc/tutorial/doc/theme/l_arr_disabled.gif | Bin 91 -> 0 bytes doc/tutorial/doc/theme/lens.gif | Bin 897 -> 0 bytes doc/tutorial/doc/theme/note.gif | Bin 151 -> 0 bytes doc/tutorial/doc/theme/python.png | Bin 14699 -> 0 bytes doc/tutorial/doc/theme/r_arr.gif | Bin 147 -> 0 bytes doc/tutorial/doc/theme/r_arr_disabled.gif | Bin 91 -> 0 bytes doc/tutorial/doc/theme/smiley.gif | Bin 879 -> 0 bytes doc/tutorial/doc/theme/style.css | 170 -- doc/tutorial/doc/theme/u_arr.gif | Bin 170 -> 0 bytes doc/tutorial/doc/using_the_interpreter.html | 270 --- ...unctions_with_default_implementations.html | 122 - 49 files changed, 5438 deletions(-) delete mode 100644 doc/tutorial/doc/auto_overloading.html delete mode 100644 doc/tutorial/doc/basic_interface.html delete mode 100644 doc/tutorial/doc/building_hello_world.html delete mode 100644 doc/tutorial/doc/call_policies.html delete mode 100644 doc/tutorial/doc/class_data_members.html delete mode 100644 doc/tutorial/doc/class_operators_special_functions.html delete mode 100644 doc/tutorial/doc/class_properties.html delete mode 100644 doc/tutorial/doc/class_virtual_functions.html delete mode 100644 doc/tutorial/doc/constructors.html delete mode 100644 doc/tutorial/doc/creating_packages.html delete mode 100644 doc/tutorial/doc/default_arguments.html delete mode 100644 doc/tutorial/doc/derived_object_types.html delete mode 100644 doc/tutorial/doc/deriving_a_python_class.html delete mode 100644 doc/tutorial/doc/embedding.html delete mode 100644 doc/tutorial/doc/enums.html delete mode 100644 doc/tutorial/doc/exception_translation.html delete mode 100644 doc/tutorial/doc/exposing_classes.html delete mode 100644 doc/tutorial/doc/extending_wrapped_objects_in_python.html delete mode 100644 doc/tutorial/doc/extracting_c___objects.html delete mode 100644 doc/tutorial/doc/functions.html delete mode 100644 doc/tutorial/doc/general_techniques.html delete mode 100644 doc/tutorial/doc/inheritance.html delete mode 100644 doc/tutorial/doc/iterators.html delete mode 100644 doc/tutorial/doc/object_interface.html delete mode 100644 doc/tutorial/doc/overloading.html delete mode 100644 doc/tutorial/doc/quickstart.html delete mode 100644 doc/tutorial/doc/quickstart.txt delete mode 100644 doc/tutorial/doc/reducing_compiling_time.html delete mode 100644 doc/tutorial/doc/theme/Thumbs.db delete mode 100644 doc/tutorial/doc/theme/alert.gif delete mode 100644 doc/tutorial/doc/theme/arrow.gif delete mode 100644 doc/tutorial/doc/theme/bkd.gif delete mode 100644 doc/tutorial/doc/theme/bkd2.gif delete mode 100644 doc/tutorial/doc/theme/bulb.gif delete mode 100644 doc/tutorial/doc/theme/bullet.gif delete mode 100644 doc/tutorial/doc/theme/c++boost.gif delete mode 100644 doc/tutorial/doc/theme/jam.png delete mode 100644 doc/tutorial/doc/theme/l_arr.gif delete mode 100644 doc/tutorial/doc/theme/l_arr_disabled.gif delete mode 100644 doc/tutorial/doc/theme/lens.gif delete mode 100644 doc/tutorial/doc/theme/note.gif delete mode 100644 doc/tutorial/doc/theme/python.png delete mode 100644 doc/tutorial/doc/theme/r_arr.gif delete mode 100644 doc/tutorial/doc/theme/r_arr_disabled.gif delete mode 100644 doc/tutorial/doc/theme/smiley.gif delete mode 100644 doc/tutorial/doc/theme/style.css delete mode 100644 doc/tutorial/doc/theme/u_arr.gif delete mode 100644 doc/tutorial/doc/using_the_interpreter.html delete mode 100644 doc/tutorial/doc/virtual_functions_with_default_implementations.html diff --git a/doc/tutorial/doc/auto_overloading.html b/doc/tutorial/doc/auto_overloading.html deleted file mode 100644 index aa6b03c8..00000000 --- a/doc/tutorial/doc/auto_overloading.html +++ /dev/null @@ -1,112 +0,0 @@ - - - -Auto-Overloading - - - - - - - - - - -
- - Auto-Overloading -
-
- - - - - - -
-

-It was mentioned in passing in the previous section that -BOOST_PYTHON_FUNCTION_OVERLOADS and BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS -can also be used for overloaded functions and member functions with a -common sequence of initial arguments. Here is an example:

-
-     void foo()
-     {
-        /*...*/
-     }
-
-     void foo(bool a)
-     {
-        /*...*/
-     }
-
-     void foo(bool a, int b)
-     {
-        /*...*/
-     }
-
-     void foo(bool a, int b, char c)
-     {
-        /*...*/
-     }
-
-

-Like in the previous section, we can generate thin wrappers for these -overloaded functions in one-shot:

-
-    BOOST_PYTHON_FUNCTION_OVERLOADS(foo_overloads, foo, 0, 3)
-
-

-Then...

-
-    .def("foo", foo, foo_overloads());
-
-

-Notice though that we have a situation now where we have a minimum of zero -(0) arguments and a maximum of 3 arguments.

-

Manual Wrapping

-It is important to emphasize however that the overloaded functions must -have a common sequence of initial arguments. Otherwise, our scheme above -will not work. If this is not the case, we have to wrap our functions - -manually.

-

-Actually, we can mix and match manual wrapping of overloaded functions and -automatic wrapping through BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS and -its sister, BOOST_PYTHON_FUNCTION_OVERLOADS. Following up on our example -presented in the section -on overloading, since the -first 4 overload functins have a common sequence of initial arguments, we -can use BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS to automatically wrap the -first three of the defs and manually wrap just the last. Here's -how we'll do this:

-
-    BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(xf_overloads, f, 1, 4)
-
-

-Create a member function pointers as above for both X::f overloads:

-
-    bool    (X::*fx1)(int, double, char)    = &X::f;
-    int     (X::*fx2)(int, int, int)        = &X::f;
-
-

-Then...

-
-    .def("f", fx1, xf_overloads());
-    .def("f", fx2)
-
- - - - - - -
-
-
- - diff --git a/doc/tutorial/doc/basic_interface.html b/doc/tutorial/doc/basic_interface.html deleted file mode 100644 index 8165b121..00000000 --- a/doc/tutorial/doc/basic_interface.html +++ /dev/null @@ -1,77 +0,0 @@ - - - -Basic Interface - - - - - - - - - - -
- - Basic Interface -
-
- - - - - - -
-

-Class object wraps PyObject*. All the intricacies of dealing with -PyObjects such as managing reference counting are handled by the -object class. C++ object interoperability is seamless. Boost.Python C++ -objects can in fact be explicitly constructed from any C++ object.

-

-To illustrate, this Python code snippet:

-
-    def f(x, y):
-         if (y == 'foo'):
-             x[3:7] = 'bar'
-         else:
-             x.items += y(3, x)
-         return x
-
-    def getfunc():
-       return f;
-
-

-Can be rewritten in C++ using Boost.Python facilities this way:

-
-    object f(object x, object y) {
-         if (y == "foo")
-             x.slice(3,7) = "bar";
-         else
-             x.attr("items") += y(3, x);
-         return x;
-    }
-    object getfunc() {
-        return object(f);
-    }
-
-

-Apart from cosmetic differences due to the fact that we are writing the -code in C++, the look and feel should be immediately apparent to the Python -coder.

- - - - - - -
-
-
- - diff --git a/doc/tutorial/doc/building_hello_world.html b/doc/tutorial/doc/building_hello_world.html deleted file mode 100644 index 61c4280c..00000000 --- a/doc/tutorial/doc/building_hello_world.html +++ /dev/null @@ -1,196 +0,0 @@ - - - -Building Hello World - - - - - - - - - - -
- - Building Hello World -
-
- - - - - - -
-

From Start To Finish

-Now the first thing you'd want to do is to build the Hello World module and -try it for yourself in Python. In this section, we shall outline the steps -necessary to achieve that. We shall use the build tool that comes bundled -with every boost distribution: bjam.

- - - - -
- Building without bjam

- -Besides bjam, there are of course other ways to get your module built. -What's written here should not be taken as "the one and only way". -There are of course other build tools apart from bjam. - -Take note however that the preferred build tool for Boost.Python is bjam. -There are so many ways to set up the build incorrectly. Experience shows -that 90% of the "I can't build Boost.Python" problems come from people -who had to use a different tool. -
-

-We shall skip over the details. Our objective will be to simply create the -hello world module and run it in Python. For a complete reference to -building Boost.Python, check out: -building.html. -After this brief bjam tutorial, we should have built two DLLs:

-

-if you are on Windows, and

-

-if you are on Unix.

-

-The tutorial example can be found in the directory: -libs/python/example/tutorial. There, you can find:

-

-The hello.cpp file is our C++ hello world example. The Jamfile is a -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. For example, a pre-built Microsoft Windows bjam executable can -be downloaded -here. -The complete list of bjam pre-built -executables can be found -here.

-

Let's Jam!

-

-

-Here is our minimalist Jamfile:

-
-    subproject libs/python/example/tutorial ;
-
-    SEARCH on python.jam = $(BOOST_BUILD_PATH) ;
-    include python.jam ;
-
-    extension hello                     # Declare a Python extension called hello
-    :   hello.cpp                       # source
-        <dll>../../build/boost_python   # dependencies
-        ;
-

-First, we need to specify our location in the boost project hierarchy. -It so happens that the tutorial example is located in /libs/python/example/tutorial. -Thus:

-
-    subproject libs/python/example/tutorial ;
-

-Then we will include the definitions needed by Python modules:

-
-    SEARCH on python.jam = $(BOOST_BUILD_PATH) ;
-    include python.jam ;
-

-Finally we declare our hello extension:

-
-    extension hello                     # Declare a Python extension called hello
-    :   hello.cpp                       # source
-        <dll>../../build/boost_python   # dependencies
-        ;
-

Running bjam

-bjam is run using your operating system's command line interpreter.

-

Start it up.

-Make sure that the environment is set so that we can invoke the C++ -compiler. With MSVC, that would mean running the Vcvars32.bat batch -file. For instance:

-
-    C:\Program Files\Microsoft Visual Studio\VC98\bin\Vcvars32.bat
-
-

-Some environment variables will have to be setup for proper building of our -Python modules. Example:

-
-    set PYTHON_ROOT=c:/dev/tools/python
-    set PYTHON_VERSION=2.2
-
-

-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. Be sure not to include a third number, e.g. not "2.2.1", -even if that's the version you have.

-

-Now we are ready... Be sure to cd to libs/python/example/tutorial -where the tutorial "hello.cpp" and the "Jamfile" is situated.

-

-Finally:

-
-    bjam -sTOOLS=msvc
-
-

-We are again assuming that we are using Microsoft Visual C++ version 6. If -not, then you will have to specify the appropriate tool. See - -Building Boost Libraries for -further details.

-

-It should be building now:

-
-    cd C:\dev\boost\libs\python\example\tutorial
-    bjam -sTOOLS=msvc
-    ...patience...
-    ...found 1703 targets...
-    ...updating 40 targets...
-

-And so on... Finally:

-
-    vc-C++ ..\..\..\..\libs\python\example\tutorial\bin\hello.pyd\msvc\debug\
-    runtime-link-dynamic\hello.obj
-    hello.cpp
-    vc-Link ..\..\..\..\libs\python\example\tutorial\bin\hello.pyd\msvc\debug\
-    runtime-link-dynamic\hello.pyd ..\..\..\..\libs\python\example\tutorial\bin\
-    hello.pyd\msvc\debug\runtime-link-dynamic\hello.lib
-       Creating library ..\..\..\..\libs\python\example\tutorial\bin\hello.pyd\
-       msvc\debug\runtime-link-dynamic\hello.lib and object ..\..\..\..\libs\python\
-       example\tutorial\bin\hello.pyd\msvc\debug\runtime-link-dynamic\hello.exp
-    ...updated 40 targets...
-

-If all is well, you should now have:

-

-if you are on Windows, and

-

-if you are on Unix.

-

-boost_python.dll can be found somewhere in libs\python\build\bin -while hello.pyd can be found somewhere in -libs\python\example\tutorial\bin. After a successful build, you can just -link in these DLLs with the Python interpreter. In Windows for example, you -can simply put these libraries inside the directory where the Python -executable is.

-

-You may now fire up Python and run our hello module:

-
-    >>> import hello
-    >>> print hello.greet()
-    hello, world
-
-

There you go... Have fun!

- - - - - -
-
-
- - diff --git a/doc/tutorial/doc/call_policies.html b/doc/tutorial/doc/call_policies.html deleted file mode 100644 index dc94ea5b..00000000 --- a/doc/tutorial/doc/call_policies.html +++ /dev/null @@ -1,169 +0,0 @@ - - - -Call Policies - - - - - - - - - - -
- - Call Policies -
-
- - - - - - -
-

-In C++, we often deal with arguments and return types such as pointers -and references. Such primitive types are rather, ummmm, low level and -they really don't tell us much. At the very least, we don't know the -owner of the pointer or the referenced object. No wonder languages -such as Java and Python never deal with such low level entities. In -C++, it's usually considered a good practice to use smart pointers -which exactly describe ownership semantics. Still, even good C++ -interfaces use raw references and pointers sometimes, so Boost.Python -must deal with them. To do this, it may need your help. Consider the -following C++ function:

-
-    X& f(Y& y, Z* z);
-
-

-How should the library wrap this function? A naive approach builds a -Python X object around result reference. This strategy might or might -not work out. Here's an example where it didn't

-
-    >>> x = f(y, z) ##x refers to some C++ X
-    >>> del y
-    >>> x.some_method() ##CRASH!
-
-

-What's the problem?

-

-Well, what if f() was implemented as shown below:

-
-    X& f(Y& y, Z* z)
-    {
-        y.z = z;
-        return y.x;
-    }
-
-

-The problem is that the lifetime of result X& is tied to the lifetime -of y, because the f() returns a reference to a member of the y -object. This idiom is is not uncommon and perfectly acceptable in the -context of C++. However, Python users should not be able to crash the -system just by using our C++ interface. In this case deleting y will -invalidate the reference to X. We have a dangling reference.

-

-Here's what's happening:

-
  1. f is called passing in a reference to y and a pointer to z
  2. A reference to y.x is returned
  3. y is deleted. x is a dangling reference
  4. x.some_method() is called
  5. BOOM!

-We could copy result into a new object:

-
-    >>> f(y, z).set(42) ##Result disappears
-    >>> y.x.get()       ##No crash, but still bad
-    3.14
-
-

-This is not really our intent of our C++ interface. We've broken our -promise that the Python interface should reflect the C++ interface as -closely as possible.

-

-Our problems do not end there. Suppose Y is implemented as follows:

-
-    struct Y
-    {
-        X x; Z* z;
-        int z_value() { return z->value(); }
-    };
-
-

-Notice that the data member z is held by class Y using a raw -pointer. Now we have a potential dangling pointer problem inside Y:

-
-    >>> x = f(y, z) ##y refers to z
-    >>> del z       ##Kill the z object
-    >>> y.z_value() ##CRASH!
-
-

-For reference, here's the implementation of f again:

-
-    X& f(Y& y, Z* z)
-    {
-        y.z = z;
-        return y.x;
-    }
-
-

-Here's what's happening:

-
  1. f is called passing in a reference to y and a pointer to z
  2. A pointer to z is held by y
  3. A reference to y.x is returned
  4. z is deleted. y.z is a dangling pointer
  5. y.z_value() is called
  6. z->value() is called
  7. BOOM!

Call Policies

-Call Policies may be used in situations such as the example detailed above. -In our example, return_internal_reference and with_custodian_and_ward -are our friends:

-
-    def("f", f,
-        return_internal_reference<1,
-            with_custodian_and_ward<1, 2> >());
-
-

-What are the 1 and 2 parameters, you ask?

-
-    return_internal_reference<1
-
-

-Informs Boost.Python that the first argument, in our case Y& y, is the -owner of the returned reference: X&. The "1" simply specifies the -first argument. In short: "return an internal reference X& owned by the -1st argument Y& y".

-
-    with_custodian_and_ward<1, 2>
-
-

-Informs Boost.Python that the lifetime of the argument indicated by ward -(i.e. the 2nd argument: Z* z) is dependent on the lifetime of the -argument indicated by custodian (i.e. the 1st argument: Y& y).

-

-It is also important to note that we have defined two policies above. Two -or more policies can be composed by chaining. Here's the general syntax:

-
-    policy1<args...,
-        policy2<args...,
-            policy3<args...> > >
-
-

-Here is the list of predefined call policies. A complete reference detailing -these can be found -here.

- - - - -
- Remember the Zen, Luke:

-"Explicit is better than implicit"
-"In the face of ambiguity, refuse the temptation to guess"
- - - - - - -
-
-
- - diff --git a/doc/tutorial/doc/class_data_members.html b/doc/tutorial/doc/class_data_members.html deleted file mode 100644 index b43bf83c..00000000 --- a/doc/tutorial/doc/class_data_members.html +++ /dev/null @@ -1,78 +0,0 @@ - - - -Class Data Members - - - - - - - - - - -
- - Class Data Members -
-
- - - - - - -
-

-Data members may also be exposed to Python so that they can be -accessed as attributes of the corresponding Python class. Each data -member that we wish to be exposed may be regarded as read-only or -read-write. Consider this class Var:

-
-    struct Var
-    {
-        Var(std::string name) : name(name), value() {}
-        std::string const name;
-        float value;
-    };
-
-

-Our C++ Var class and its data members can be exposed to Python:

-
-    class_<Var>("Var", init<std::string>())
-        .def_readonly("name", &Var::name)
-        .def_readwrite("value", &Var::value);
-
-

-Then, in Python, assuming we have placed our Var class inside the namespace -hello as we did before:

-
-    >>> x = hello.Var('pi')
-    >>> x.value = 3.14
-    >>> print x.name, 'is around', x.value
-    pi is around 3.14
-
-

-Note that name is exposed as read-only while value is exposed -as read-write.

-
-    >>> x.name = 'e' # can't change name
-    Traceback (most recent call last):
-      File "<stdin>", line 1, in ?
-    AttributeError: can't set attribute
-
- - - - - -
-
-
- - diff --git a/doc/tutorial/doc/class_operators_special_functions.html b/doc/tutorial/doc/class_operators_special_functions.html deleted file mode 100644 index ce7aab66..00000000 --- a/doc/tutorial/doc/class_operators_special_functions.html +++ /dev/null @@ -1,109 +0,0 @@ - - - -Class Operators/Special Functions - - - - - - - - - - -
- - Class Operators/Special Functions -
-
- - - - - - -
-

Python Operators

-C is well known for the abundance of operators. C++ extends this to the -extremes by allowing operator overloading. Boost.Python takes advantage of -this and makes it easy to wrap C++ operator-powered classes.

-

-Consider a file position class FilePos and a set of operators that take -on FilePos instances:

-
-    class FilePos { /*...*/ };
-
-    FilePos     operator+(FilePos, int);
-    FilePos     operator+(int, FilePos);
-    int         operator-(FilePos, FilePos);
-    FilePos     operator-(FilePos, int);
-    FilePos&    operator+=(FilePos&, int);
-    FilePos&    operator-=(FilePos&, int);
-    bool        operator<(FilePos, FilePos);
-
-

-The class and the various operators can be mapped to Python rather easily -and intuitively:

-
-    class_<FilePos>("FilePos")
-        .def(self + int())          // __add__
-        .def(int() + self)          // __radd__
-        .def(self - self)           // __sub__
-        .def(self - int())          // __sub__
-        .def(self += int())         // __iadd__
-        .def(self -= other<int>())
-        .def(self < self);          // __lt__
-
-

-The code snippet above is very clear and needs almost no explanation at -all. It is virtually the same as the operators' signatures. Just take -note that self refers to FilePos object. Also, not every class T that -you might need to interact with in an operator expression is (cheaply) -default-constructible. You can use other<T>() in place of an actual -T instance when writing "self expressions".

-

Special Methods

-Python has a few more Special Methods. Boost.Python supports all of the -standard special method names supported by real Python class instances. A -similar set of intuitive interfaces can also be used to wrap C++ functions -that correspond to these Python special functions. Example:

-
-    class Rational
-    { operator double() const; };
-
-    Rational pow(Rational, Rational);
-    Rational abs(Rational);
-    ostream& operator<<(ostream&,Rational);
-
-    class_<Rational>()
-        .def(float_(self))                  // __float__
-        .def(pow(self, other<Rational>))    // __pow__
-        .def(abs(self))                     // __abs__
-        .def(str(self))                     // __str__
-        ;
-
-

-Need we say more?

- - - - -
- What is the business of operator<< .def(str(self))? -Well, the method str requires the operator<< to do its work (i.e. -operator<< is used by the method defined by def(str(self)).
- - - - - - -
-
-
- - diff --git a/doc/tutorial/doc/class_properties.html b/doc/tutorial/doc/class_properties.html deleted file mode 100644 index 99f340c4..00000000 --- a/doc/tutorial/doc/class_properties.html +++ /dev/null @@ -1,81 +0,0 @@ - - - -Class Properties - - - - - - - - - - -
- - Class Properties -
-
- - - - - - -
-

-In C++, classes with public data members are usually frowned -upon. Well designed classes that take advantage of encapsulation hide -the class' data members. The only way to access the class' data is -through access (getter/setter) functions. Access functions expose class -properties. Here's an example:

-
-    struct Num
-    {
-        Num();
-        float get() const;
-        void set(float value);
-        ...
-    };
-
-

-However, in Python attribute access is fine; it doesn't neccessarily break -encapsulation to let users handle attributes directly, because the -attributes can just be a different syntax for a method call. Wrapping our -Num class using Boost.Python:

-
-    class_<Num>("Num")
-        .add_property("rovalue", &Num::get)
-        .add_property("value", &Num::get, &Num::set);
-
-

-And at last, in Python:

-
-    >>> x = Num()
-    >>> x.value = 3.14
-    >>> x.value, x.rovalue
-    (3.14, 3.14)
-    >>> x.rovalue = 2.17 ##error!
-
-

-Take note that the class property rovalue is exposed as read-only -since the rovalue setter member function is not passed in:

-
-    .add_property("rovalue", &Num::get)
-
- - - - - - -
-
-
- - diff --git a/doc/tutorial/doc/class_virtual_functions.html b/doc/tutorial/doc/class_virtual_functions.html deleted file mode 100644 index ddc73d04..00000000 --- a/doc/tutorial/doc/class_virtual_functions.html +++ /dev/null @@ -1,141 +0,0 @@ - - - -Class Virtual Functions - - - - - - - - - - -
- - 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:

-
-    struct 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:

-
-    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;
-    };
-
- - - - -
- member function and methods

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.

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

- - - - - - -
-
-
- - diff --git a/doc/tutorial/doc/constructors.html b/doc/tutorial/doc/constructors.html deleted file mode 100644 index 809bfee3..00000000 --- a/doc/tutorial/doc/constructors.html +++ /dev/null @@ -1,102 +0,0 @@ - - - -Constructors - - - - - - - - - - -
- - Constructors -
-
- - - - - - -
-

-Our previous example didn't have any explicit constructors. -Since World is declared as a plain struct, it has an implicit default -constructor. Boost.Python exposes the default constructor by default, -which is why we were able to write

-
-    >>> planet = hello.World()
-
-

-We may wish to wrap a class with a non-default constructor. Let us -build on our previous example:

-
-    struct World
-    {
-        World(std::string msg): msg(msg) {} // added constructor
-        void set(std::string msg) { this->msg = msg; }
-        std::string greet() { return msg; }
-        std::string msg;
-    };
-
-

-This time World has no default constructor; our previous -wrapping code would fail to compile when the library tried to expose -it. We have to tell class_<World> about the constructor we want to -expose instead.

-
-    #include <boost/python.hpp>
-    using namespace boost::python;
-
-    BOOST_PYTHON_MODULE(hello)
-    {
-        class_<World>("World", init<std::string>())
-            .def("greet", &World::greet)
-            .def("set", &World::set)
-        ;
-    }
-
-

-init<std::string>() exposes the constructor taking in a -std::string (in Python, constructors are spelled -""__init__"").

-

-We can expose additional constructors by passing more init<...>s to -the def() member function. Say for example we have another World -constructor taking in two doubles:

-
-    class_<World>("World", init<std::string>())
-        .def(init<double, double>())
-        .def("greet", &World::greet)
-        .def("set", &World::set)
-    ;
-
-

-On the other hand, if we do not wish to expose any constructors at -all, we may use no_init instead:

-
-    class_<Abstract>("Abstract", no_init)
-
-

-This actually adds an __init__ method which always raises a -Python RuntimeError exception.

- - - - - - -
-
-
- - diff --git a/doc/tutorial/doc/creating_packages.html b/doc/tutorial/doc/creating_packages.html deleted file mode 100644 index fc05287e..00000000 --- a/doc/tutorial/doc/creating_packages.html +++ /dev/null @@ -1,210 +0,0 @@ - - - -Creating Packages - - - - - - - - - - -
- - Creating Packages -
-
- - - - - - -
-

-A Python package is a collection of modules that provide to the user a certain -functionality. If you're not familiar on how to create packages, a good -introduction to them is provided in the - -Python Tutorial.

-

-But we are wrapping C++ code, using Boost.Python. How can we provide a nice -package interface to our users? To better explain some concepts, let's work -with an example.

-

-We have a C++ library that works with sounds: reading and writing various -formats, applying filters to the sound data, etc. It is named (conveniently) -sounds. Our library already has a neat C++ namespace hierarchy, like so:

-
-    sounds::core
-    sounds::io
-    sounds::filters
-
-

-We would like to present this same hierarchy to the Python user, allowing him -to write code like this:

-
-    import sounds.filters
-    sounds.filters.echo(...) ##echo is a C++ function
-
-

-The first step is to write the wrapping code. We have to export each module -separately with Boost.Python, like this:

-
-    /* file core.cpp */
-    BOOST_PYTHON_MODULE(core)
-    {
-        /* export everything in the sounds::core namespace */
-        ...
-    }
-
-    /* file io.cpp */
-    BOOST_PYTHON_MODULE(io)
-    {
-        /* export everything in the sounds::io namespace */
-        ...
-    }
-
-    /* file filters.cpp */
-    BOOST_PYTHON_MODULE(filters)
-    {
-        /* export everything in the sounds::filters namespace */
-        ...
-    }
-
-

-Compiling these files will generate the following Python extensions: -core.pyd, io.pyd and filters.pyd.

- - - - -
- The extension .pyd is used for python extension modules, which -are just shared libraries. Using the default for your system, like .so for -Unix and .dll for Windows, works just as well.
-

-Now, we create this directory structure for our Python package:

-
-    sounds/
-        __init__.py
-        core.pyd
-        filters.pyd
-        io.pyd
-

-The file __init__.py is what tells Python that the directory sounds/ is -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 and fire up the interpreter:

-
-    >>> import sounds.io
-    >>> import sounds.filters
-    >>> sound = sounds.io.open('file.mp3')
-    >>> new_sound = sounds.filters.echo(sound, 1.0)
-
-

-Nice heh?

-

-This is the simplest way to create hierarchies of packages, but it is not very -flexible. What if we want to add a pure Python function to the filters -package, for instance, one that applies 3 filters in a sound object at once? -Sure, you can do this in C++ and export it, but why not do so in Python? You -don't have to recompile the extension modules, plus it will be easier to write -it.

-

-If we want this flexibility, we will have to complicate our package hierarchy a -little. First, we will have to change the name of the extension modules:

-
-    /* file core.cpp */
-    BOOST_PYTHON_MODULE(_core)
-    {
-        ...
-        /* export everything in the sounds::core namespace */
-    }
-
-

-Note that we added an underscore to the module name. The filename will have to -be changed to _core.pyd as well, and we do the same to the other extension modules. -Now, we change our package hierarchy like so:

-
-    sounds/
-        __init__.py
-        core/
-            __init__.py
-            _core.pyd
-        filters/
-            __init__.py
-            _filters.pyd
-        io/
-            __init__.py
-            _io.pyd
-

-Note that we created a directory for each extension module, and added a -__init__.py to each one. But if we leave it that way, the user will have to -access the functions in the core module with this syntax:

-
-    >>> import sounds.core._core
-    >>> sounds.core._core.foo(...)
-
-

-which is not what we want. But here enters the __init__.py magic: everything -that is brought to the __init__.py namespace can be accessed directly by the -user. So, all we have to do is bring the entire namespace from _core.pyd -to core/__init__.py. So add this line of code to sounds/core/__init__.py:

-
-    from _core import *
-
-

-We do the same for the other packages. Now the user accesses the functions and -classes in the extension modules like before:

-
-    >>> import sounds.filters
-    >>> sounds.filters.echo(...)
-
-

-with the additional benefit that we can easily add pure Python functions to -any module, in a way that the user can't tell the difference between a C++ -function and a Python function. Let's add a pure Python function, -echo_noise, to the filters package. This function applies both the -echo and noise filters in sequence in the given sound object. We -create a file named sounds/filters/echo_noise.py and code our function:

-
-    import _filters
-    def echo_noise(sound):
-        s = _filters.echo(sound)
-        s = _filters.noise(sound)
-        return s
-
-

-Next, we add this line to sounds/filters/__init__.py:

-
-    from echo_noise import echo_noise
-
-

-And that's it. The user now accesses this function like any other function -from the filters package:

-
-    >>> import sounds.filters
-    >>> sounds.filters.echo_noise(...)
-
- - - - - - -
-
-
- - diff --git a/doc/tutorial/doc/default_arguments.html b/doc/tutorial/doc/default_arguments.html deleted file mode 100644 index 51402380..00000000 --- a/doc/tutorial/doc/default_arguments.html +++ /dev/null @@ -1,158 +0,0 @@ - - - -Default Arguments - - - - - - - - - - -
- - Default Arguments -
-
- - - - - - -
-

-Boost.Python wraps (member) function pointers. Unfortunately, C++ function -pointers carry no default argument info. Take a function f with default -arguments:

-
-    int f(int, double = 3.14, char const* = "hello");
-
-

-But the type of a pointer to the function f has no information -about its default arguments:

-
-    int(*g)(int,double,char const*) = f;    // defaults lost!
-
-

-When we pass this function pointer to the def function, there is no way -to retrieve the default arguments:

-
-    def("f", f);                            // defaults lost!
-
-

-Because of this, when wrapping C++ code, we had to resort to manual -wrapping as outlined in the -previous section, or -writing thin wrappers:

-
-    // write "thin wrappers"
-    int f1(int x) { f(x); }
-    int f2(int x, double y) { f(x,y); }
-
-    /*...*/
-
-        // in module init
-        def("f", f);  // all arguments
-        def("f", f2); // two arguments
-        def("f", f1); // one argument
-
-

-When you want to wrap functions (or member functions) that either:

-

BOOST_PYTHON_FUNCTION_OVERLOADS

-Boost.Python now has a way to make it easier. For instance, given a function:

-
-    int foo(int a, char b = 1, unsigned c = 2, double d = 3)
-    {
-        /*...*/
-    }
-
-

-The macro invocation:

-
-    BOOST_PYTHON_FUNCTION_OVERLOADS(foo_overloads, foo, 1, 4)
-
-

-will automatically create the thin wrappers for us. This macro will create -a class foo_overloads that can be passed on to def(...). The third -and fourth macro argument are the minimum arguments and maximum arguments, -respectively. In our foo function the minimum number of arguments is 1 -and the maximum number of arguments is 4. The def(...) function will -automatically add all the foo variants for us:

-
-    def("foo", foo, foo_overloads());
-
-

BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS

-Objects here, objects there, objects here there everywhere. More frequently -than anything else, we need to expose member functions of our classes to -Python. Then again, we have the same inconveniences as before when default -arguments or overloads with a common sequence of initial arguments come -into play. Another macro is provided to make this a breeze.

-

-Like BOOST_PYTHON_FUNCTION_OVERLOADS, -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS may be used to automatically create -the thin wrappers for wrapping member functions. Let's have an example:

-
-    struct george
-    {
-        void
-        wack_em(int a, int b = 0, char c = 'x')
-        {
-            /*...*/
-        }
-    };
-
-

-The macro invocation:

-
-    BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(george_overloads, wack_em, 1, 3)
-
-

-will generate a set of thin wrappers for george's wack_em member function -accepting a minimum of 1 and a maximum of 3 arguments (i.e. the third and -fourth macro argument). The thin wrappers are all enclosed in a class named -george_overloads that can then be used as an argument to def(...):

-
-    .def("wack_em", &george::wack_em, george_overloads());
-
-

-See the -overloads reference -for details.

-

init and optional

-A similar facility is provided for class constructors, again, with -default arguments or a sequence of overloads. Remember init<...>? For example, -given a class X with a constructor:

-
-    struct X
-    {
-        X(int a, char b = 'D', std::string c = "constructor", double d = 0.0);
-        /*...*/
-    }
-
-

-You can easily add this constructor to Boost.Python in one shot:

-
-    .def(init<int, optional<char, std::string, double> >())
-
-

-Notice the use of init<...> and optional<...> to signify the default -(optional arguments).

- - - - - - -
-
-
- - diff --git a/doc/tutorial/doc/derived_object_types.html b/doc/tutorial/doc/derived_object_types.html deleted file mode 100644 index fbe44584..00000000 --- a/doc/tutorial/doc/derived_object_types.html +++ /dev/null @@ -1,117 +0,0 @@ - - - -Derived Object types - - - - - - - - - - -
- - Derived Object types -
-
- - - - - - -
-

-Boost.Python comes with a set of derived object types corresponding to -that of Python's:

-

-These derived object types act like real Python types. For instance:

-
-    str(1) ==> "1"
-
-

-Wherever appropriate, a particular derived object has corresponding -Python type's methods. For instance, dict has a keys() method:

-
-    d.keys()
-
-

-make_tuple is provided for declaring tuple literals. Example:

-
-    make_tuple(123, 'D', "Hello, World", 0.0);
-
-

-In C++, when Boost.Python objects are used as arguments to functions, -subtype matching is required. For example, when a function f, as -declared below, is wrapped, it will only accept instances of Python's -str type and subtypes.

-
-    void f(str name)
-    {
-        object n2 = name.attr("upper")();   // NAME = name.upper()
-        str NAME = name.upper();            // better
-        object msg = "%s is bigger than %s" % make_tuple(NAME,name);
-    }
-
-

-In finer detail:

-
-    str NAME = name.upper();
-
-

-Illustrates that we provide versions of the str type's methods as C++ -member functions.

-
-    object msg = "%s is bigger than %s" % make_tuple(NAME,name);
-
-

-Demonstrates that you can write the C++ equivalent of "format" % x,y,z -in Python, which is useful since there's no easy way to do that in std C++.

-

- Beware the common pitfall of forgetting that the constructors -of most of Python's mutable types make copies, just as in Python.

-

-Python:

-
-    >>> d = dict(x.__dict__)     ##copies x.__dict__
-    >>> d['whatever']            ##modifies the copy
-
-

-C++:

-
-    dict d(x.attr("__dict__"));  ##copies x.__dict__
-    d['whatever'] = 3;           ##modifies the copy
-
-

class_<T> as objects

-Due to the dynamic nature of Boost.Python objects, any class_<T> may -also be one of these types! The following code snippet wraps the class -(type) object.

-

-We can use this to create wrapped instances. Example:

-
-    object vec345 = (
-        class_<Vec2>("Vec2", init<double, double>())
-            .def_readonly("length", &Point::length)
-            .def_readonly("angle", &Point::angle)
-        )(3.0, 4.0);
-
-    assert(vec345.attr("length") == 5.0);
-
- - - - - - -
-
-
- - diff --git a/doc/tutorial/doc/deriving_a_python_class.html b/doc/tutorial/doc/deriving_a_python_class.html deleted file mode 100644 index 5c268371..00000000 --- a/doc/tutorial/doc/deriving_a_python_class.html +++ /dev/null @@ -1,83 +0,0 @@ - - - -Deriving a Python Class - - - - - - - - - - -
- - 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:

-
  1. call_f(derived) is called in Python
  2. This corresponds to def("call_f", call_f);. Boost.Python dispatches this call.
  3. int call_f(Base& b) { return b.f(); } accepts the call.
  4. The overridden virtual function f of BaseWrap is called.
  5. call_method<int>(self, "f"); dispatches the call back to Python.
  6. def f(self): return 42 is finally called.
- - - - - -
-
-
- - diff --git a/doc/tutorial/doc/embedding.html b/doc/tutorial/doc/embedding.html deleted file mode 100644 index 4b0e4069..00000000 --- a/doc/tutorial/doc/embedding.html +++ /dev/null @@ -1,97 +0,0 @@ - - - -Embedding - - - - - - - - - - -
- - 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 - -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...

-

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

-
-    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) ;
-

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:

-
  1. #include <boost/python.hpp>

  2. Call -Py_Initialize() to start the interpreter and create the __main__ module.

  3. Call other Python C API routines to use the interpreter.

  4. 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...

- - - - - -
-
-
- - diff --git a/doc/tutorial/doc/enums.html b/doc/tutorial/doc/enums.html deleted file mode 100644 index 09632e31..00000000 --- a/doc/tutorial/doc/enums.html +++ /dev/null @@ -1,95 +0,0 @@ - - - -Enums - - - - - - - - - - -
- - Enums -
-
- - - - - - -
-

-Boost.Python has a nifty facility to capture and wrap C++ enums. While -Python has no enum type, we'll often want to expose our C++ enums to -Python as an int. Boost.Python's enum facility makes this easy while -taking care of the proper conversions from Python's dynamic typing to C++'s -strong static typing (in C++, ints cannot be implicitly converted to -enums). To illustrate, given a C++ enum:

-
-    enum choice { red, blue };
-
-

-the construct:

-
-    enum_<choice>("choice")
-        .value("red", red)
-        .value("blue", blue)
-        ;
-
-

-can be used to expose to Python. The new enum type is created in the -current scope(), which is usually the current module. The snippet above -creates a Python class derived from Python's int type which is -associated with the C++ type passed as its first parameter.

- - - - -
- what is a scope?

The scope is a class that has an -associated global Python object which controls the Python namespace in -which new extension classes and wrapped functions will be defined as -attributes. Details can be found -here.
-

-You can access those values in Python as

-
-    >>> my_module.choice.red
-    my_module.choice.red
-
-

-where my_module is the module where the enum is declared. You can also -create a new scope around a class:

-
-    scope in_X = class_<X>("X")
-                    .def( ... )
-                    .def( ... )
-                ;
-
-    // Expose X::nested as X.nested
-    enum_<X::nested>("nested")
-        .value("red", red)
-        .value("blue", blue)
-        ;
-
- - - - - - -
-
-
- - diff --git a/doc/tutorial/doc/exception_translation.html b/doc/tutorial/doc/exception_translation.html deleted file mode 100644 index 48079d2b..00000000 --- a/doc/tutorial/doc/exception_translation.html +++ /dev/null @@ -1,61 +0,0 @@ - - - -Exception Translation - - - - - - - - - - -
- - Exception Translation -
-
- - - - - - -
-

-All C++ exceptions must be caught at the boundary with Python code. This -boundary is the point where C++ meets Python. Boost.Python provides a -default exception handler that translates selected standard exceptions, -then gives up:

-
-    raise RuntimeError, 'unidentifiable C++ Exception'
-
-

-Users may provide custom translation. Here's an example:

-
-    struct PodBayDoorException;
-    void translator(PodBayDoorException const& x) {
-        PyErr_SetString(PyExc_UserWarning, "I'm sorry Dave...");
-    }
-    BOOST_PYTHON_MODULE(kubrick) {
-         register_exception_translator<
-              PodBayDoorException>(translator);
-         ...
-
- - - - - - -
-
-
- - diff --git a/doc/tutorial/doc/exposing_classes.html b/doc/tutorial/doc/exposing_classes.html deleted file mode 100644 index 18f2e8d0..00000000 --- a/doc/tutorial/doc/exposing_classes.html +++ /dev/null @@ -1,79 +0,0 @@ - - - -Exposing Classes - - - - - - - - - - -
- - Exposing Classes -
-
- - - - - - -
-

-Now let's expose a C++ class to Python.

-

-Consider a C++ class/struct that we want to expose to Python:

-
-    struct World
-    {
-        void set(std::string msg) { this->msg = msg; }
-        std::string greet() { return msg; }
-        std::string msg;
-    };
-
-

-We can expose this to Python by writing a corresponding Boost.Python -C++ Wrapper:

-
-    #include <boost/python.hpp>
-    using namespace boost::python;
-
-    BOOST_PYTHON_MODULE(hello)
-    {
-        class_<World>("World")
-            .def("greet", &World::greet)
-            .def("set", &World::set)
-        ;
-    }
-
-

-Here, we wrote a C++ class wrapper that exposes the member functions -greet and set. Now, after building our module as a shared library, we -may use our class World in Python. Here's a sample Python session:

-
-    >>> import hello
-    >>> planet = hello.World()
-    >>> planet.set('howdy')
-    >>> planet.greet()
-    'howdy'
-
- - - - - - -
-
-
- - diff --git a/doc/tutorial/doc/extending_wrapped_objects_in_python.html b/doc/tutorial/doc/extending_wrapped_objects_in_python.html deleted file mode 100644 index df0c7945..00000000 --- a/doc/tutorial/doc/extending_wrapped_objects_in_python.html +++ /dev/null @@ -1,134 +0,0 @@ - - - -Extending Wrapped Objects in Python - - - - - - - - - - -
- - Extending Wrapped Objects in Python -
-
- - - - - - -
-

-Thanks to Python's flexibility, you can easily add new methods to a class, -even after it was already created:

-
-    >>> class C(object): pass
-    >>>
-    >>> ##a regular function
-    >>> def C_str(self): return 'A C instance!'
-    >>>
-    >>> ##now we turn it in a member function
-    >>> C.__str__ = C_str
-    >>>
-    >>> c = C()
-    >>> print c
-    A C instance!
-    >>> C_str(c)
-    A C instance!
-
-

-Yes, Python rox.

-

-We can do the same with classes that were wrapped with Boost.Python. Suppose -we have a class point in C++:

-
-    class point {...};
-
-    BOOST_PYTHON_MODULE(_geom)
-    {
-        class_<point>("point")...;
-    }
-
-

-If we are using the technique from the previous session, - -Creating Packages, we can code directly into geom/__init__.py:

-
-    from _geom import *
-
-    ##a regular function
-    def point_str(self):
-        return str((self.x, self.y))
-
-    ##now we turn it into a member function
-    point.__str__ = point_str
-
-

-All point instances created from C++ will also have this member function! -This technique has several advantages:

-

-You can even add a little syntactic sugar with the use of metaclasses. Let's -create a special metaclass that "injects" methods in other classes.

-
-    ##The one Boost.Python uses for all wrapped classes.
-    ##You can use here any class exported by Boost instead of "point"
-    BoostPythonMetaclass = point.__class__
-
-    class injector(object):
-        class __metaclass__(BoostPythonMetaclass):
-            def __init__(self, name, bases, dict):
-                for b in bases:
-                    if type(b) not in (self, type):
-                        for k,v in dict.items():
-                            setattr(b,k,v)
-                return type.__init__(self, name, bases, dict)
-
-    ##inject some methods in the point foo
-    class more_point(injector, point):
-        def __repr__(self):
-            return 'Point(x=%s, y=%s)' % (self.x, self.y)
-        def foo(self):
-            print 'foo!'
-
-

-Now let's see how it got:

-
-    >>> print point()
-    Point(x=10, y=10)
-    >>> point().foo()
-    foo!
-
-

-Another useful idea is to replace constructors with factory functions:

-
-    _point = point
-
-    def point(x=0, y=0):
-        return _point(x, y)
-
-

-In this simple case there is not much gained, but for constructurs with -many overloads and/or arguments this is often a great simplification, again -with virtually zero memory footprint and zero compile-time overhead for -the keyword support.

- - - - - - -
-
-
- - diff --git a/doc/tutorial/doc/extracting_c___objects.html b/doc/tutorial/doc/extracting_c___objects.html deleted file mode 100644 index 82096e6d..00000000 --- a/doc/tutorial/doc/extracting_c___objects.html +++ /dev/null @@ -1,79 +0,0 @@ - - - -Extracting C++ objects - - - - - - - - - - -
- - Extracting C++ objects -
-
- - - - - - -
-

-At some point, we will need to get C++ values out of object instances. This -can be achieved with the extract<T> function. Consider the following:

-
-    double x = o.attr("length"); // compile error
-
-

-In the code above, we got a compiler error because Boost.Python -object can't be implicitly converted to doubles. Instead, what -we wanted to do above can be achieved by writing:

-
-    double l = extract<double>(o.attr("length"));
-    Vec2& v = extract<Vec2&>(o);
-    assert(l == v.length());
-
-

-The first line attempts to extract the "length" attribute of the -Boost.Python object o. The second line attempts to extract the -Vec2 object from held by the Boost.Python object o.

-

-Take note that we said "attempt to" above. What if the Boost.Python -object o does not really hold a Vec2 type? This is certainly -a possibility considering the dynamic nature of Python objects. To -be on the safe side, if the C++ type can't be extracted, an -appropriate exception is thrown. To avoid an exception, we need to -test for extractibility:

-
-    extract<Vec2&> x(o);
-    if (x.check()) {
-        Vec2& v = x(); ...
-
-

- The astute reader might have noticed that the extract<T> -facility in fact solves the mutable copying problem:

-
-    dict d = extract<dict>(x.attr("__dict__"));
-    d['whatever'] = 3;          ##modifies x.__dict__ !
-
- - - - - - -
-
-
- - diff --git a/doc/tutorial/doc/functions.html b/doc/tutorial/doc/functions.html deleted file mode 100644 index 6a29d89b..00000000 --- a/doc/tutorial/doc/functions.html +++ /dev/null @@ -1,73 +0,0 @@ - - - -Functions - - - - - - - - - - -
- - Functions -
-
- - - - - - -
-

-In this chapter, we'll look at Boost.Python powered functions in closer -detail. We shall see some facilities to make exposing C++ functions to -Python safe from potential pifalls such as dangling pointers and -references. We shall also see facilities that will make it even easier for -us to expose C++ functions that take advantage of C++ features such as -overloading and default arguments.

-

Read on...

-But before you do, you might want to fire up Python 2.2 or later and type ->>> import this.

-
-    >>> import this
-    The Zen of Python, by Tim Peters
-    Beautiful is better than ugly.
-    Explicit is better than implicit.
-    Simple is better than complex.
-    Complex is better than complicated.
-    Flat is better than nested.
-    Sparse is better than dense.
-    Readability counts.
-    Special cases aren't special enough to break the rules.
-    Although practicality beats purity.
-    Errors should never pass silently.
-    Unless explicitly silenced.
-    In the face of ambiguity, refuse the temptation to guess.
-    There should be one-- and preferably only one --obvious way to do it
-    Although that way may not be obvious at first unless you're Dutch.
-    Now is better than never.
-    Although never is often better than *right* now.
-    If the implementation is hard to explain, it's a bad idea.
-    If the implementation is easy to explain, it may be a good idea.
-    Namespaces are one honking great idea -- let's do more of those!
-
- - - - - -
-
-
- - diff --git a/doc/tutorial/doc/general_techniques.html b/doc/tutorial/doc/general_techniques.html deleted file mode 100644 index 3ed48a8e..00000000 --- a/doc/tutorial/doc/general_techniques.html +++ /dev/null @@ -1,43 +0,0 @@ - - - -General Techniques - - - - - - - - - - -
- - General Techniques -
-
- - - - - - -
-

-Here are presented some useful techniques that you can use while wrapping code with Boost.Python.

- - - - - - -
-
-
- - diff --git a/doc/tutorial/doc/inheritance.html b/doc/tutorial/doc/inheritance.html deleted file mode 100644 index acd18942..00000000 --- a/doc/tutorial/doc/inheritance.html +++ /dev/null @@ -1,98 +0,0 @@ - - - -Inheritance - - - - - - - - - - -
- - Inheritance -
-
- - - - - - -
-

-In the previous examples, we dealt with classes that are not polymorphic. -This is not often the case. Much of the time, we will be wrapping -polymorphic classes and class hierarchies related by inheritance. We will -often have to write Boost.Python wrappers for classes that are derived from -abstract base classes.

-

-Consider this trivial inheritance structure:

-
-    struct Base { virtual ~Base(); };
-    struct Derived : Base {};
-
-

-And a set of C++ functions operating on Base and Derived object -instances:

-
-    void b(Base*);
-    void d(Derived*);
-    Base* factory() { return new Derived; }
-
-

-We've seen how we can wrap the base class Base:

-
-    class_<Base>("Base")
-        /*...*/
-        ;
-
-

-Now we can inform Boost.Python of the inheritance relationship between -Derived and its base class Base. Thus:

-
-    class_<Derived, bases<Base> >("Derived")
-        /*...*/
-        ;
-
-

-Doing so, we get some things for free:

-
  1. Derived automatically inherits all of Base's Python methods (wrapped C++ member functions)
  2. 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:

-
-    def("b", b);
-    def("d", d);
-    def("factory", factory);
-
-

-Note that free function factory is being used to generate new -instances of class Derived. In such cases, we use -return_value_policy<manage_new_object> to instruct Python to adopt -the pointer to Base and hold the instance in a new Python Base -object until the the Python object is destroyed. We shall see more of -Boost.Python -call policies later.

-
-    // Tell Python to take ownership of factory's result
-    def("factory", factory,
-        return_value_policy<manage_new_object>());
-
- - - - - - -
-
-
- - diff --git a/doc/tutorial/doc/iterators.html b/doc/tutorial/doc/iterators.html deleted file mode 100644 index 585f89b1..00000000 --- a/doc/tutorial/doc/iterators.html +++ /dev/null @@ -1,101 +0,0 @@ - - - -Iterators - - - - - - - - - - -
- - Iterators -
-
- - - - - - -
-

-In C++, and STL in particular, we see iterators everywhere. Python also has -iterators, but these are two very different beasts.

-

-C++ iterators:

-

-Python Iterators:

-

-The typical Python iteration protocol: for y in x... is as follows:

-
-    iter = x.__iter__()         ##get iterator
-    try:
-        while 1:
-        y = iter.next()         ##get each item
-        ...                     ##process y
-    except StopIteration: pass  ##iterator exhausted
-
-

-Boost.Python provides some mechanisms to make C++ iterators play along -nicely as Python iterators. What we need to do is to produce -appropriate __iter__ function from C++ iterators that is compatible -with the Python iteration protocol. For example:

-
-    object get_iterator = iterator<vector<int> >();
-    object iter = get_iterator(v);
-    object first = iter.next();
-
-

-Or for use in class_<>:

-
-    .def("__iter__", iterator<vector<int> >())
-
-

-range

-

-We can create a Python savvy iterator using the range function:

-

-Here, start/finish may be one of:

-

-iterator

-

-Given a container T, iterator is a shortcut that simply calls range -with &T::begin, &T::end.

-

-Let's put this into action... Here's an example from some hypothetical -bogon Particle accelerator code:

-
-    f = Field()
-    for x in f.pions:
-        smash(x)
-    for y in f.bogons:
-        count(y)
-
-

-Now, our C++ Wrapper:

-
-    class_<F>("Field")
-        .property("pions", range(&F::p_begin, &F::p_end))
-        .property("bogons", range(&F::b_begin, &F::b_end));
-
- - - - - - -
-
-
- - diff --git a/doc/tutorial/doc/object_interface.html b/doc/tutorial/doc/object_interface.html deleted file mode 100644 index 1988dcd7..00000000 --- a/doc/tutorial/doc/object_interface.html +++ /dev/null @@ -1,54 +0,0 @@ - - - -Object Interface - - - - - - - - - - -
- - Object Interface -
-
- - - - - - -
-

-Python is dynamically typed, unlike C++ which is statically typed. Python -variables may hold an integer, a float, list, dict, tuple, str, long etc., -among other things. In the viewpoint of Boost.Python and C++, these -Pythonic variables are just instances of class object. We shall see in -this chapter how to deal with Python objects.

-

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

-

-

- - - - - - -
-
-
- - diff --git a/doc/tutorial/doc/overloading.html b/doc/tutorial/doc/overloading.html deleted file mode 100644 index f93edcac..00000000 --- a/doc/tutorial/doc/overloading.html +++ /dev/null @@ -1,88 +0,0 @@ - - - -Overloading - - - - - - - - - - -
- - Overloading -
-
- - - - - - -
-

-The following illustrates a scheme for manually wrapping an overloaded -member functions. Of course, the same technique can be applied to wrapping -overloaded non-member functions.

-

-We have here our C++ class:

-
-    struct X
-    {
-        bool f(int a)
-        {
-            return true;
-        }
-
-        bool f(int a, double b)
-        {
-            return true;
-        }
-
-        bool f(int a, double b, char c)
-        {
-            return true;
-        }
-
-        int f(int a, int b, int c)
-        {
-            return a + b + c;
-        };
-    };
-
-

-Class X has 4 overloaded functions. We shall start by introducing some -member function pointer variables:

-
-    bool    (X::*fx1)(int)              = &X::f;
-    bool    (X::*fx2)(int, double)      = &X::f;
-    bool    (X::*fx3)(int, double, char)= &X::f;
-    int     (X::*fx4)(int, int, int)    = &X::f;
-
-

-With these in hand, we can proceed to define and wrap this for Python:

-
-    .def("f", fx1)
-    .def("f", fx2)
-    .def("f", fx3)
-    .def("f", fx4)
-
- - - - - - -
-
-
- - diff --git a/doc/tutorial/doc/quickstart.html b/doc/tutorial/doc/quickstart.html deleted file mode 100644 index 02ba7a1a..00000000 --- a/doc/tutorial/doc/quickstart.html +++ /dev/null @@ -1,79 +0,0 @@ - - - -QuickStart - - - - - - - - - -
- - QuickStart -
-
- - - - - - -
-

-The Boost Python Library is a framework for interfacing Python and -C++. It allows you to quickly and seamlessly expose C++ classes -functions and objects to Python, and vice-versa, using no special -tools -- just your C++ compiler. It is designed to wrap C++ interfaces -non-intrusively, so that you should not have to change the C++ code at -all in order to wrap it, making Boost.Python ideal for exposing -3rd-party libraries to Python. The library's use of advanced -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

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

-
-    char const* greet()
-    {
-       return "hello, world";
-    }
-
-

-can be exposed to Python by writing a Boost.Python wrapper:

-
-    #include <boost/python.hpp>
-    using namespace boost::python;
-
-    BOOST_PYTHON_MODULE(hello)
-    {
-        def("greet", greet);
-    }
-
-

-That's it. We're done. We can now build this as a shared library. The -resulting DLL is now visible to Python. Here's a sample Python session:

-
-    >>> import hello
-    >>> print hello.greet()
-    hello, world
-
-

Next stop... Building your Hello World module from start to finish...

- - - - - -
-
-
- - diff --git a/doc/tutorial/doc/quickstart.txt b/doc/tutorial/doc/quickstart.txt deleted file mode 100644 index 0e202c0b..00000000 --- a/doc/tutorial/doc/quickstart.txt +++ /dev/null @@ -1,2047 +0,0 @@ -[doc Boost Python Tutorial] - -[def __note__ [$theme/note.gif]] -[def __alert__ [$theme/alert.gif]] -[def __detail__ [$theme/lens.gif]] -[def __tip__ [$theme/bulb.gif]] -[def :-) [$theme/smiley.gif]] - -[page QuickStart] - -The Boost Python Library is a framework for interfacing Python and -C++. It allows you to quickly and seamlessly expose C++ classes -functions and objects to Python, and vice-versa, using no special -tools -- just your C++ compiler. It is designed to wrap C++ interfaces -non-intrusively, so that you should not have to change the C++ code at -all in order to wrap it, making Boost.Python ideal for exposing -3rd-party libraries to Python. The library's use of advanced -metaprogramming techniques simplifies its syntax for users, so that -wrapping code takes on the look of a kind of declarative interface -definition language (IDL). - -[h2 Hello World] - -Following C/C++ tradition, let's start with the "hello, world". A C++ -Function: - - char const* greet() - { - return "hello, world"; - } - -can be exposed to Python by writing a Boost.Python wrapper: - - #include - using namespace boost::python; - - BOOST_PYTHON_MODULE(hello) - { - def("greet", greet); - } - -That's it. We're done. We can now build this as a shared library. The -resulting DLL is now visible to Python. Here's a sample Python session: - - >>> import hello - >>> print hello.greet() - hello, world - -[:['[*Next stop... Building your Hello World module from start to finish...]]] - -[page Building Hello World] - -[h2 From Start To Finish] - -Now the first thing you'd want to do is to build the Hello World module and -try it for yourself in Python. In this section, we shall outline the steps -necessary to achieve that. We shall use the build tool that comes bundled -with every boost distribution: [*bjam]. - -[blurb __detail__ [*Building without bjam][br][br] - -Besides bjam, there are of course other ways to get your module built. -What's written here should not be taken as "the one and only way". -There are of course other build tools apart from [^bjam]. - -Take note however that the preferred build tool for Boost.Python is bjam. -There are so many ways to set up the build incorrectly. Experience shows -that 90% of the "I can't build Boost.Python" problems come from people -who had to use a different tool. -] - -We shall skip over the details. Our objective will be to simply create the -hello world module and run it in Python. For a complete reference to -building Boost.Python, check out: [@../../building.html building.html]. -After this brief ['bjam] tutorial, we should have built two DLLs: - -* boost_python.dll -* hello.pyd - -if you are on Windows, and - -* libboost_python.so -* hello.so - -if you are on Unix. - -The tutorial example can be found in the directory: -[^libs/python/example/tutorial]. There, you can find: - -* hello.cpp -* Jamfile - -The [^hello.cpp] file is our C++ hello world example. The [^Jamfile] is a -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. For example, a pre-built Microsoft Windows bjam executable can -be downloaded [@http://boost.sourceforge.net/jam-executables/bin.ntx86/bjam.zip here]. -The complete list of bjam pre-built -executables can be found [@../../../../../tools/build/index.html#Jam here]. - -[h2 Let's Jam!] -[$theme/jam.png] - -Here is our minimalist Jamfile: - -[pre - subproject libs/python/example/tutorial ; - - SEARCH on python.jam = $(BOOST_BUILD_PATH) ; - include python.jam ; - - extension hello # Declare a Python extension called hello - : hello.cpp # source - ../../build/boost_python # dependencies - ; -] - -First, we need to specify our location in the boost project hierarchy. -It so happens that the tutorial example is located in [^/libs/python/example/tutorial]. -Thus: - -[pre - subproject libs/python/example/tutorial ; -] - -Then we will include the definitions needed by Python modules: - -[pre - SEARCH on python.jam = $(BOOST_BUILD_PATH) ; - include python.jam ; -] - -Finally we declare our [^hello] extension: - -[pre - extension hello # Declare a Python extension called hello - : hello.cpp # source - ../../build/boost_python # dependencies - ; -] - -[h2 Running bjam] - -['bjam] is run using your operating system's command line interpreter. - -[:Start it up.] - -Make sure that the environment is set so that we can invoke the C++ -compiler. With MSVC, that would mean running the [^Vcvars32.bat] batch -file. For instance: - - C:\Program Files\Microsoft Visual Studio\VC98\bin\Vcvars32.bat - -Some environment variables will have to be setup for proper building of our -Python modules. Example: - - set PYTHON_ROOT=c:/dev/tools/python - set PYTHON_VERSION=2.2 - -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. __note__ Be sure not to include a third number, e.g. [*not] "2.2.1", -even if that's the version you have. - -Now we are ready... Be sure to [^cd] to [^libs/python/example/tutorial] -where the tutorial [^"hello.cpp"] and the [^"Jamfile"] is situated. - -Finally: - - bjam -sTOOLS=msvc - -We are again assuming that we are using Microsoft Visual C++ version 6. If -not, then you will have to specify the appropriate tool. See -[@../../../../../tools/build/index.html Building Boost Libraries] for -further details. - -It should be building now: - -[pre - cd C:\dev\boost\libs\python\example\tutorial - bjam -sTOOLS=msvc - ...patience... - ...found 1703 targets... - ...updating 40 targets... -] - -And so on... Finally: - -[pre - vc-C++ ..\..\..\..\libs\python\example\tutorial\bin\hello.pyd\msvc\debug\ - runtime-link-dynamic\hello.obj - hello.cpp - vc-Link ..\..\..\..\libs\python\example\tutorial\bin\hello.pyd\msvc\debug\ - runtime-link-dynamic\hello.pyd ..\..\..\..\libs\python\example\tutorial\bin\ - hello.pyd\msvc\debug\runtime-link-dynamic\hello.lib - Creating library ..\..\..\..\libs\python\example\tutorial\bin\hello.pyd\ - msvc\debug\runtime-link-dynamic\hello.lib and object ..\..\..\..\libs\python\ - example\tutorial\bin\hello.pyd\msvc\debug\runtime-link-dynamic\hello.exp - ...updated 40 targets... -] - -If all is well, you should now have: - -* boost_python.dll -* hello.pyd - -if you are on Windows, and - -* libboost_python.so -* hello.so - -if you are on Unix. - -[^boost_python.dll] can be found somewhere in [^libs\python\build\bin] -while [^hello.pyd] can be found somewhere in -[^libs\python\example\tutorial\bin]. After a successful build, you can just -link in these DLLs with the Python interpreter. In Windows for example, you -can simply put these libraries inside the directory where the Python -executable is. - -You may now fire up Python and run our hello module: - - >>> import hello - >>> print hello.greet() - hello, world - -[:[*There you go... Have fun!]] - -[page Exposing Classes] - -Now let's expose a C++ class to Python. - -Consider a C++ class/struct that we want to expose to Python: - - struct World - { - void set(std::string msg) { this->msg = msg; } - std::string greet() { return msg; } - std::string msg; - }; - -We can expose this to Python by writing a corresponding Boost.Python -C++ Wrapper: - - #include - using namespace boost::python; - - BOOST_PYTHON_MODULE(hello) - { - class_("World") - .def("greet", &World::greet) - .def("set", &World::set) - ; - } - -Here, we wrote a C++ class wrapper that exposes the member functions -[^greet] and [^set]. Now, after building our module as a shared library, we -may use our class [^World] in Python. Here's a sample Python session: - - >>> import hello - >>> planet = hello.World() - >>> planet.set('howdy') - >>> planet.greet() - 'howdy' - -[page:1 Constructors] - -Our previous example didn't have any explicit constructors. -Since [^World] is declared as a plain struct, it has an implicit default -constructor. Boost.Python exposes the default constructor by default, -which is why we were able to write - - >>> planet = hello.World() - -We may wish to wrap a class with a non-default constructor. Let us -build on our previous example: - - struct World - { - World(std::string msg): msg(msg) {} // added constructor - void set(std::string msg) { this->msg = msg; } - std::string greet() { return msg; } - std::string msg; - }; - -This time [^World] has no default constructor; our previous -wrapping code would fail to compile when the library tried to expose -it. We have to tell [^class_] about the constructor we want to -expose instead. - - #include - using namespace boost::python; - - BOOST_PYTHON_MODULE(hello) - { - class_("World", init()) - .def("greet", &World::greet) - .def("set", &World::set) - ; - } - -[^init()] exposes the constructor taking in a -[^std::string] (in Python, constructors are spelled -"[^"__init__"]"). - -We can expose additional constructors by passing more [^init<...>]s to -the [^def()] member function. Say for example we have another World -constructor taking in two doubles: - - class_("World", init()) - .def(init()) - .def("greet", &World::greet) - .def("set", &World::set) - ; - -On the other hand, if we do not wish to expose any constructors at -all, we may use [^no_init] instead: - - class_("Abstract", no_init) - -This actually adds an [^__init__] method which always raises a -Python RuntimeError exception. - -[page:1 Class Data Members] - -Data members may also be exposed to Python so that they can be -accessed as attributes of the corresponding Python class. Each data -member that we wish to be exposed may be regarded as [*read-only] or -[*read-write]. Consider this class [^Var]: - - struct Var - { - Var(std::string name) : name(name), value() {} - std::string const name; - float value; - }; - -Our C++ [^Var] class and its data members can be exposed to Python: - - class_("Var", init()) - .def_readonly("name", &Var::name) - .def_readwrite("value", &Var::value); - -Then, in Python, assuming we have placed our Var class inside the namespace -hello as we did before: - - >>> x = hello.Var('pi') - >>> x.value = 3.14 - >>> print x.name, 'is around', x.value - pi is around 3.14 - -Note that [^name] is exposed as [*read-only] while [^value] is exposed -as [*read-write]. - -[pre - >>> x.name = 'e' # can't change name - Traceback (most recent call last): - File "", line 1, in ? - AttributeError: can't set attribute -] - -[page:1 Class Properties] - -In C++, classes with public data members are usually frowned -upon. Well designed classes that take advantage of encapsulation hide -the class' data members. The only way to access the class' data is -through access (getter/setter) functions. Access functions expose class -properties. Here's an example: - - struct Num - { - Num(); - float get() const; - void set(float value); - ... - }; - -However, in Python attribute access is fine; it doesn't neccessarily break -encapsulation to let users handle attributes directly, because the -attributes can just be a different syntax for a method call. Wrapping our -[^Num] class using Boost.Python: - - class_("Num") - .add_property("rovalue", &Num::get) - .add_property("value", &Num::get, &Num::set); - -And at last, in Python: - - >>> x = Num() - >>> x.value = 3.14 - >>> x.value, x.rovalue - (3.14, 3.14) - >>> x.rovalue = 2.17 # error! - -Take note that the class property [^rovalue] is exposed as [*read-only] -since the [^rovalue] setter member function is not passed in: - - .add_property("rovalue", &Num::get) - -[page:1 Inheritance] - -In the previous examples, we dealt with classes that are not polymorphic. -This is not often the case. Much of the time, we will be wrapping -polymorphic classes and class hierarchies related by inheritance. We will -often have to write Boost.Python wrappers for classes that are derived from -abstract base classes. - -Consider this trivial inheritance structure: - - struct Base { virtual ~Base(); }; - struct Derived : Base {}; - -And a set of C++ functions operating on [^Base] and [^Derived] object -instances: - - void b(Base*); - void d(Derived*); - Base* factory() { return new Derived; } - -We've seen how we can wrap the base class [^Base]: - - class_("Base") - /*...*/ - ; - -Now we can inform Boost.Python of the inheritance relationship between -[^Derived] and its base class [^Base]. Thus: - - class_ >("Derived") - /*...*/ - ; - -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. - -Now, we shall expose the C++ free functions [^b] and [^d] and [^factory]: - - def("b", b); - def("d", d); - def("factory", factory); - -Note that free function [^factory] is being used to generate new -instances of class [^Derived]. In such cases, we use -[^return_value_policy] to instruct Python to adopt -the pointer to [^Base] and hold the instance in a new Python [^Base] -object until the the Python object is destroyed. We shall see more of -Boost.Python [@call_policies.html call policies] later. - - // Tell Python to take ownership of factory's result - def("factory", factory, - return_value_policy()); - -[page:1 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: - - struct 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: - - 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(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(self, "f"); } - int default_f() { return Base::f(); } // <<=== ***ADDED*** - PyObject* self; - }; - -[blurb __detail__ [*member function and methods][br][br] 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?][br][br] - -['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."[br][br] - -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.[br][br] - -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. - -[page:1 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. - -[page:1 Virtual Functions with Default Implementations] - -Recall that in the [@class_virtual_functions.html 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 - { - virtual int f() = 0; - }; - -had a pure virtual function [^f]. If, however, its member function [^f] was -not declared as pure virtual: - - struct 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 - { - BaseWrap(PyObject* self_) - : self(self_) {} - int f() { return call_method(self, "f"); } - int default_f() { return Base::f(); } // <<=== ***ADDED*** - PyObject* self; - }; - -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: - - 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]. - -In Python, the results would be as expected: - - >>> base = Base() - >>> class Derived(Base): - ... def f(self): - ... return 42 - ... - >>> derived = Derived() - -Calling [^base.f()]: - - >>> base.f() - 0 - -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 - -[page:1 Class Operators/Special Functions] - -[h2 Python Operators] - -C is well known for the abundance of operators. C++ extends this to the -extremes by allowing operator overloading. Boost.Python takes advantage of -this and makes it easy to wrap C++ operator-powered classes. - -Consider a file position class [^FilePos] and a set of operators that take -on FilePos instances: - - class FilePos { /*...*/ }; - - FilePos operator+(FilePos, int); - FilePos operator+(int, FilePos); - int operator-(FilePos, FilePos); - FilePos operator-(FilePos, int); - FilePos& operator+=(FilePos&, int); - FilePos& operator-=(FilePos&, int); - bool operator<(FilePos, FilePos); - -The class and the various operators can be mapped to Python rather easily -and intuitively: - - class_("FilePos") - .def(self + int()) // __add__ - .def(int() + self) // __radd__ - .def(self - self) // __sub__ - .def(self - int()) // __sub__ - .def(self += int()) // __iadd__ - .def(self -= other()) - .def(self < self); // __lt__ - -The code snippet above is very clear and needs almost no explanation at -all. It is virtually the same as the operators' signatures. Just take -note that [^self] refers to FilePos object. Also, not every class [^T] that -you might need to interact with in an operator expression is (cheaply) -default-constructible. You can use [^other()] in place of an actual -[^T] instance when writing "self expressions". - -[h2 Special Methods] - -Python has a few more ['Special Methods]. Boost.Python supports all of the -standard special method names supported by real Python class instances. A -similar set of intuitive interfaces can also be used to wrap C++ functions -that correspond to these Python ['special functions]. Example: - - class Rational - { operator double() const; }; - - Rational pow(Rational, Rational); - Rational abs(Rational); - ostream& operator<<(ostream&,Rational); - - class_() - .def(float_(self)) // __float__ - .def(pow(self, other)) // __pow__ - .def(abs(self)) // __abs__ - .def(str(self)) // __str__ - ; - -Need we say more? - -[blurb __detail__ What is the business of [^operator<<] [^.def(str(self))]? -Well, the method [^str] requires the [^operator<<] to do its work (i.e. -[^operator<<] is used by the method defined by def(str(self)).] - -[page Functions] - -In this chapter, we'll look at Boost.Python powered functions in closer -detail. We shall see some facilities to make exposing C++ functions to -Python safe from potential pifalls such as dangling pointers and -references. We shall also see facilities that will make it even easier for -us to expose C++ functions that take advantage of C++ features such as -overloading and default arguments. - -[:['Read on...]] - -But before you do, you might want to fire up Python 2.2 or later and type -[^>>> import this]. - -[pre - >>> import this - The Zen of Python, by Tim Peters - Beautiful is better than ugly. - Explicit is better than implicit. - Simple is better than complex. - Complex is better than complicated. - Flat is better than nested. - Sparse is better than dense. - Readability counts. - Special cases aren't special enough to break the rules. - Although practicality beats purity. - Errors should never pass silently. - Unless explicitly silenced. - In the face of ambiguity, refuse the temptation to guess. - There should be one-- and preferably only one --obvious way to do it - Although that way may not be obvious at first unless you're Dutch. - Now is better than never. - Although never is often better than *right* now. - If the implementation is hard to explain, it's a bad idea. - If the implementation is easy to explain, it may be a good idea. - Namespaces are one honking great idea -- let's do more of those! -] - -[page:1 Call Policies] - -In C++, we often deal with arguments and return types such as pointers -and references. Such primitive types are rather, ummmm, low level and -they really don't tell us much. At the very least, we don't know the -owner of the pointer or the referenced object. No wonder languages -such as Java and Python never deal with such low level entities. In -C++, it's usually considered a good practice to use smart pointers -which exactly describe ownership semantics. Still, even good C++ -interfaces use raw references and pointers sometimes, so Boost.Python -must deal with them. To do this, it may need your help. Consider the -following C++ function: - - X& f(Y& y, Z* z); - -How should the library wrap this function? A naive approach builds a -Python X object around result reference. This strategy might or might -not work out. Here's an example where it didn't - - >>> x = f(y, z) # x refers to some C++ X - >>> del y - >>> x.some_method() # CRASH! - -What's the problem? - -Well, what if f() was implemented as shown below: - - X& f(Y& y, Z* z) - { - y.z = z; - return y.x; - } - -The problem is that the lifetime of result X& is tied to the lifetime -of y, because the f() returns a reference to a member of the y -object. This idiom is is not uncommon and perfectly acceptable in the -context of C++. However, Python users should not be able to crash the -system just by using our C++ interface. In this case deleting y will -invalidate the reference to X. We have a dangling reference. - -Here's what's happening: - -# [^f] is called passing in a reference to [^y] and a pointer to [^z] -# A reference to [^y.x] is returned -# [^y] is deleted. [^x] is a dangling reference -# [^x.some_method()] is called -# [*BOOM!] - -We could copy result into a new object: - - >>> f(y, z).set(42) # Result disappears - >>> y.x.get() # No crash, but still bad - 3.14 - -This is not really our intent of our C++ interface. We've broken our -promise that the Python interface should reflect the C++ interface as -closely as possible. - -Our problems do not end there. Suppose Y is implemented as follows: - - struct Y - { - X x; Z* z; - int z_value() { return z->value(); } - }; - -Notice that the data member [^z] is held by class Y using a raw -pointer. Now we have a potential dangling pointer problem inside Y: - - >>> x = f(y, z) # y refers to z - >>> del z # Kill the z object - >>> y.z_value() # CRASH! - -For reference, here's the implementation of [^f] again: - - X& f(Y& y, Z* z) - { - y.z = z; - return y.x; - } - -Here's what's happening: - -# [^f] is called passing in a reference to [^y] and a pointer to [^z] -# A pointer to [^z] is held by [^y] -# A reference to [^y.x] is returned -# [^z] is deleted. [^y.z] is a dangling pointer -# [^y.z_value()] is called -# [^z->value()] is called -# [*BOOM!] - -[h2 Call Policies] - -Call Policies may be used in situations such as the example detailed above. -In our example, [^return_internal_reference] and [^with_custodian_and_ward] -are our friends: - - def("f", f, - return_internal_reference<1, - with_custodian_and_ward<1, 2> >()); - -What are the [^1] and [^2] parameters, you ask? - - return_internal_reference<1 - -Informs Boost.Python that the first argument, in our case [^Y& y], is the -owner of the returned reference: [^X&]. The "[^1]" simply specifies the -first argument. In short: "return an internal reference [^X&] owned by the -1st argument [^Y& y]". - - with_custodian_and_ward<1, 2> - -Informs Boost.Python that the lifetime of the argument indicated by ward -(i.e. the 2nd argument: [^Z* z]) is dependent on the lifetime of the -argument indicated by custodian (i.e. the 1st argument: [^Y& y]). - -It is also important to note that we have defined two policies above. Two -or more policies can be composed by chaining. Here's the general syntax: - - policy1 > > - -Here is the list of predefined call policies. A complete reference detailing -these can be found [@../../v2/reference.html#models_of_call_policies here]. - -* [*with_custodian_and_ward][br] Ties lifetimes of the arguments -* [*with_custodian_and_ward_postcall][br] Ties lifetimes of the arguments and results -* [*return_internal_reference][br] Ties lifetime of one argument to that of result -* [*return_value_policy with T one of:][br] -* [*reference_existing_object][br]naïve (dangerous) approach -* [*copy_const_reference][br]Boost.Python v1 approach -* [*copy_non_const_reference][br] -* [*manage_new_object][br] Adopt a pointer and hold the instance - -[blurb :-) [*Remember the Zen, Luke:][br][br] -"Explicit is better than implicit"[br] -"In the face of ambiguity, refuse the temptation to guess"[br]] - -[page:1 Overloading] - -The following illustrates a scheme for manually wrapping an overloaded -member functions. Of course, the same technique can be applied to wrapping -overloaded non-member functions. - -We have here our C++ class: - - struct X - { - bool f(int a) - { - return true; - } - - bool f(int a, double b) - { - return true; - } - - bool f(int a, double b, char c) - { - return true; - } - - int f(int a, int b, int c) - { - return a + b + c; - }; - }; - -Class X has 4 overloaded functions. We shall start by introducing some -member function pointer variables: - - bool (X::*fx1)(int) = &X::f; - bool (X::*fx2)(int, double) = &X::f; - bool (X::*fx3)(int, double, char)= &X::f; - int (X::*fx4)(int, int, int) = &X::f; - -With these in hand, we can proceed to define and wrap this for Python: - - .def("f", fx1) - .def("f", fx2) - .def("f", fx3) - .def("f", fx4) - -[page:1 Default Arguments] - -Boost.Python wraps (member) function pointers. Unfortunately, C++ function -pointers carry no default argument info. Take a function [^f] with default -arguments: - - int f(int, double = 3.14, char const* = "hello"); - -But the type of a pointer to the function [^f] has no information -about its default arguments: - - int(*g)(int,double,char const*) = f; // defaults lost! - -When we pass this function pointer to the [^def] function, there is no way -to retrieve the default arguments: - - def("f", f); // defaults lost! - -Because of this, when wrapping C++ code, we had to resort to manual -wrapping as outlined in the [@overloading.html previous section], or -writing thin wrappers: - - // write "thin wrappers" - int f1(int x) { f(x); } - int f2(int x, double y) { f(x,y); } - - /*...*/ - - // in module init - def("f", f); // all arguments - def("f", f2); // two arguments - def("f", f1); // one argument - -When you want to wrap functions (or member functions) that either: - -* have default arguments, or -* are overloaded with a common sequence of initial arguments - -[h2 BOOST_PYTHON_FUNCTION_OVERLOADS] - -Boost.Python now has a way to make it easier. For instance, given a function: - - int foo(int a, char b = 1, unsigned c = 2, double d = 3) - { - /*...*/ - } - -The macro invocation: - - BOOST_PYTHON_FUNCTION_OVERLOADS(foo_overloads, foo, 1, 4) - -will automatically create the thin wrappers for us. This macro will create -a class [^foo_overloads] that can be passed on to [^def(...)]. The third -and fourth macro argument are the minimum arguments and maximum arguments, -respectively. In our [^foo] function the minimum number of arguments is 1 -and the maximum number of arguments is 4. The [^def(...)] function will -automatically add all the foo variants for us: - - def("foo", foo, foo_overloads()); - -[h2 BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS] - -Objects here, objects there, objects here there everywhere. More frequently -than anything else, we need to expose member functions of our classes to -Python. Then again, we have the same inconveniences as before when default -arguments or overloads with a common sequence of initial arguments come -into play. Another macro is provided to make this a breeze. - -Like [^BOOST_PYTHON_FUNCTION_OVERLOADS], -[^BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS] may be used to automatically create -the thin wrappers for wrapping member functions. Let's have an example: - - struct george - { - void - wack_em(int a, int b = 0, char c = 'x') - { - /*...*/ - } - }; - -The macro invocation: - - BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(george_overloads, wack_em, 1, 3) - -will generate a set of thin wrappers for george's [^wack_em] member function -accepting a minimum of 1 and a maximum of 3 arguments (i.e. the third and -fourth macro argument). The thin wrappers are all enclosed in a class named -[^george_overloads] that can then be used as an argument to [^def(...)]: - - .def("wack_em", &george::wack_em, george_overloads()); - -See the [@../../v2/overloads.html#BOOST_PYTHON_FUNCTION_OVERLOADS-spec overloads reference] -for details. - -[h2 init and optional] - -A similar facility is provided for class constructors, again, with -default arguments or a sequence of overloads. Remember [^init<...>]? For example, -given a class X with a constructor: - - struct X - { - X(int a, char b = 'D', std::string c = "constructor", double d = 0.0); - /*...*/ - } - -You can easily add this constructor to Boost.Python in one shot: - - .def(init >()) - -Notice the use of [^init<...>] and [^optional<...>] to signify the default -(optional arguments). - -[page:1 Auto-Overloading] - -It was mentioned in passing in the previous section that -[^BOOST_PYTHON_FUNCTION_OVERLOADS] and [^BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS] -can also be used for overloaded functions and member functions with a -common sequence of initial arguments. Here is an example: - - void foo() - { - /*...*/ - } - - void foo(bool a) - { - /*...*/ - } - - void foo(bool a, int b) - { - /*...*/ - } - - void foo(bool a, int b, char c) - { - /*...*/ - } - -Like in the previous section, we can generate thin wrappers for these -overloaded functions in one-shot: - - BOOST_PYTHON_FUNCTION_OVERLOADS(foo_overloads, foo, 0, 3) - -Then... - - .def("foo", foo, foo_overloads()); - -Notice though that we have a situation now where we have a minimum of zero -(0) arguments and a maximum of 3 arguments. - -[h2 Manual Wrapping] - -It is important to emphasize however that [*the overloaded functions must -have a common sequence of initial arguments]. Otherwise, our scheme above -will not work. If this is not the case, we have to wrap our functions -[@overloading.html manually]. - -Actually, we can mix and match manual wrapping of overloaded functions and -automatic wrapping through [^BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS] and -its sister, [^BOOST_PYTHON_FUNCTION_OVERLOADS]. Following up on our example -presented in the section [@overloading.html on overloading], since the -first 4 overload functins have a common sequence of initial arguments, we -can use [^BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS] to automatically wrap the -first three of the [^def]s and manually wrap just the last. Here's -how we'll do this: - - BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(xf_overloads, f, 1, 4) - -Create a member function pointers as above for both X::f overloads: - - bool (X::*fx1)(int, double, char) = &X::f; - int (X::*fx2)(int, int, int) = &X::f; - -Then... - - .def("f", fx1, xf_overloads()); - .def("f", fx2) - -[page Object Interface] - -Python is dynamically typed, unlike C++ which is statically typed. Python -variables may hold an integer, a float, list, dict, tuple, str, long etc., -among other things. In the viewpoint of Boost.Python and C++, these -Pythonic variables are just instances of class [^object]. We shall see in -this chapter how to deal with Python objects. - -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++ [^object]s are as close as possible to Python. This -should minimize the learning curve significantly. - -[$theme/python.png] - -[page:1 Basic Interface] - -Class [^object] wraps [^PyObject*]. All the intricacies of dealing with -[^PyObject]s such as managing reference counting are handled by the -[^object] class. C++ object interoperability is seamless. Boost.Python C++ -[^object]s can in fact be explicitly constructed from any C++ object. - -To illustrate, this Python code snippet: - - def f(x, y): - if (y == 'foo'): - x[3:7] = 'bar' - else: - x.items += y(3, x) - return x - - def getfunc(): - return f; - -Can be rewritten in C++ using Boost.Python facilities this way: - - object f(object x, object y) { - if (y == "foo") - x.slice(3,7) = "bar"; - else - x.attr("items") += y(3, x); - return x; - } - object getfunc() { - return object(f); - } - -Apart from cosmetic differences due to the fact that we are writing the -code in C++, the look and feel should be immediately apparent to the Python -coder. - -[page:1 Derived Object types] - -Boost.Python comes with a set of derived [^object] types corresponding to -that of Python's: - -* list -* dict -* tuple -* str -* long_ -* enum - -These derived [^object] types act like real Python types. For instance: - - str(1) ==> "1" - -Wherever appropriate, a particular derived [^object] has corresponding -Python type's methods. For instance, [^dict] has a [^keys()] method: - - d.keys() - -[^make_tuple] is provided for declaring ['tuple literals]. Example: - - make_tuple(123, 'D', "Hello, World", 0.0); - -In C++, when Boost.Python [^object]s are used as arguments to functions, -subtype matching is required. For example, when a function [^f], as -declared below, is wrapped, it will only accept instances of Python's -[^str] type and subtypes. - - void f(str name) - { - object n2 = name.attr("upper")(); // NAME = name.upper() - str NAME = name.upper(); // better - object msg = "%s is bigger than %s" % make_tuple(NAME,name); - } - -In finer detail: - - str NAME = name.upper(); - -Illustrates that we provide versions of the str type's methods as C++ -member functions. - - object msg = "%s is bigger than %s" % make_tuple(NAME,name); - -Demonstrates that you can write the C++ equivalent of [^"format" % x,y,z] -in Python, which is useful since there's no easy way to do that in std C++. - -__alert__ [*Beware] the common pitfall of forgetting that the constructors -of most of Python's mutable types make copies, just as in Python. - -Python: - - >>> d = dict(x.__dict__) # copies x.__dict__ - >>> d['whatever'] # modifies the copy - -C++: - - dict d(x.attr("__dict__")); # copies x.__dict__ - d['whatever'] = 3; # modifies the copy - -[h2 class_ as objects] - -Due to the dynamic nature of Boost.Python objects, any [^class_] may -also be one of these types! The following code snippet wraps the class -(type) object. - -We can use this to create wrapped instances. Example: - - object vec345 = ( - class_("Vec2", init()) - .def_readonly("length", &Point::length) - .def_readonly("angle", &Point::angle) - )(3.0, 4.0); - - assert(vec345.attr("length") == 5.0); - -[page:1 Extracting C++ objects] - -At some point, we will need to get C++ values out of object instances. This -can be achieved with the [^extract] function. Consider the following: - - double x = o.attr("length"); // compile error - -In the code above, we got a compiler error because Boost.Python -[^object] can't be implicitly converted to [^double]s. Instead, what -we wanted to do above can be achieved by writing: - - double l = extract(o.attr("length")); - Vec2& v = extract(o); - assert(l == v.length()); - -The first line attempts to extract the "length" attribute of the -Boost.Python [^object] [^o]. The second line attempts to ['extract] the -[^Vec2] object from held by the Boost.Python [^object] [^o]. - -Take note that we said "attempt to" above. What if the Boost.Python -[^object] [^o] does not really hold a [^Vec2] type? This is certainly -a possibility considering the dynamic nature of Python [^object]s. To -be on the safe side, if the C++ type can't be extracted, an -appropriate exception is thrown. To avoid an exception, we need to -test for extractibility: - - extract x(o); - if (x.check()) { - Vec2& v = x(); ... - -__tip__ The astute reader might have noticed that the [^extract] -facility in fact solves the mutable copying problem: - - dict d = extract(x.attr("__dict__")); - d['whatever'] = 3; # modifies x.__dict__ ! - - -[page:1 Enums] - -Boost.Python has a nifty facility to capture and wrap C++ enums. While -Python has no [^enum] type, we'll often want to expose our C++ enums to -Python as an [^int]. Boost.Python's enum facility makes this easy while -taking care of the proper conversions from Python's dynamic typing to C++'s -strong static typing (in C++, ints cannot be implicitly converted to -enums). To illustrate, given a C++ enum: - - enum choice { red, blue }; - -the construct: - - enum_("choice") - .value("red", red) - .value("blue", blue) - ; - -can be used to expose to Python. The new enum type is created in the -current [^scope()], which is usually the current module. The snippet above -creates a Python class derived from Python's [^int] type which is -associated with the C++ type passed as its first parameter. - -[blurb __detail__ [*what is a scope?][br][br] The scope is a class that has an -associated global Python object which controls the Python namespace in -which new extension classes and wrapped functions will be defined as -attributes. Details can be found [@../../v2/scope.html here].] - -You can access those values in Python as - - >>> my_module.choice.red - my_module.choice.red - -where my_module is the module where the enum is declared. You can also -create a new scope around a class: - - scope in_X = class_("X") - .def( ... ) - .def( ... ) - ; - - // Expose X::nested as X.nested - enum_("nested") - .value("red", red) - .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] and -[@../../v2/object.html object] class templates to automate the process. - -[h2 Reference-counting handles and objects] - -There are two ways in which a function in the Python/C API can return a -[^PyObject*]: as a ['borrowed reference] or as a ['new reference]. Which of -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: - - object main_module(( - handle<>(borrowed(PyImport_AddModule("__main__"))))); - - object main_namespace = main_module.attr("__dict__"); - -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: - - object main_module(( - handle<>(borrowed(PyImport_AddModule("__main__"))))); - - object main_namespace = main_module.attr("__dict__"); - - handle<> ignored((PyRun_String( - - "hello = file('hello.txt', 'w')\n" - "hello.write('Hello world!')\n" - "hello.close()" - - , Py_file_input - , main_namespace.ptr() - , main_namespace.ptr()) - )); - -Because the Python/C API doesn't know anything about [^object]s, we used -the object's [^ptr] member function to retrieve the [^PyObject*]. - -This should create a file called 'hello.txt' in the current directory -containing a phrase that is well-known in programming circles. - -__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 -above, and in the [@object_interface.html previous section]: the aptly -named [^object] class and it's derivatives. We've already seen that they -can be constructed from a [^handle]. The following examples should further -illustrate this fact: - - object main_module(( - handle<>(borrowed(PyImport_AddModule("__main__"))))); - - object main_namespace = main_module.attr("__dict__"); - - handle<> ignored((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 -iterators, but these are two very different beasts. - -[*C++ iterators:] - -* C++ has 5 type categories (random-access, bidirectional, forward, input, output) -* There are 2 Operation categories: reposition, access -* A pair of iterators is needed to represent a (first/last) range. - -[*Python Iterators:] - -* 1 category (forward) -* 1 operation category (next()) -* Raises StopIteration exception at end - -The typical Python iteration protocol: [^[*for y in x...]] is as follows: - - iter = x.__iter__() # get iterator - try: - while 1: - y = iter.next() # get each item - ... # process y - except StopIteration: pass # iterator exhausted - -Boost.Python provides some mechanisms to make C++ iterators play along -nicely as Python iterators. What we need to do is to produce -appropriate __iter__ function from C++ iterators that is compatible -with the Python iteration protocol. For example: - - object get_iterator = iterator >(); - object iter = get_iterator(v); - object first = iter.next(); - -Or for use in class_<>: - - .def("__iter__", iterator >()) - -[*range] - -We can create a Python savvy iterator using the range function: - -* range(start, finish) -* range(start, finish) - -Here, start/finish may be one of: - -* member data pointers -* member function pointers -* adaptable function object (use Target parameter) - -[*iterator] - -* iterator() - -Given a container [^T], iterator is a shortcut that simply calls [^range] -with &T::begin, &T::end. - -Let's put this into action... Here's an example from some hypothetical -bogon Particle accelerator code: - - f = Field() - for x in f.pions: - smash(x) - for y in f.bogons: - count(y) - -Now, our C++ Wrapper: - - class_("Field") - .property("pions", range(&F::p_begin, &F::p_end)) - .property("bogons", range(&F::b_begin, &F::b_end)); - -[page Exception Translation] - -All C++ exceptions must be caught at the boundary with Python code. This -boundary is the point where C++ meets Python. Boost.Python provides a -default exception handler that translates selected standard exceptions, -then gives up: - - raise RuntimeError, 'unidentifiable C++ Exception' - -Users may provide custom translation. Here's an example: - - struct PodBayDoorException; - void translator(PodBayDoorException const& x) { - PyErr_SetString(PyExc_UserWarning, "I'm sorry Dave..."); - } - BOOST_PYTHON_MODULE(kubrick) { - register_exception_translator< - PodBayDoorException>(translator); - ... - -[page General Techniques] - -Here are presented some useful techniques that you can use while wrapping code with Boost.Python. - -[page:1 Creating Packages] - -A Python package is a collection of modules that provide to the user a certain -functionality. If you're not familiar on how to create packages, a good -introduction to them is provided in the -[@http://www.python.org/doc/current/tut/node8.html Python Tutorial]. - -But we are wrapping C++ code, using Boost.Python. How can we provide a nice -package interface to our users? To better explain some concepts, let's work -with an example. - -We have a C++ library that works with sounds: reading and writing various -formats, applying filters to the sound data, etc. It is named (conveniently) -[^sounds]. Our library already has a neat C++ namespace hierarchy, like so: - - sounds::core - sounds::io - sounds::filters - -We would like to present this same hierarchy to the Python user, allowing him -to write code like this: - - import sounds.filters - sounds.filters.echo(...) # echo is a C++ function - -The first step is to write the wrapping code. We have to export each module -separately with Boost.Python, like this: - - /* file core.cpp */ - BOOST_PYTHON_MODULE(core) - { - /* export everything in the sounds::core namespace */ - ... - } - - /* file io.cpp */ - BOOST_PYTHON_MODULE(io) - { - /* export everything in the sounds::io namespace */ - ... - } - - /* file filters.cpp */ - BOOST_PYTHON_MODULE(filters) - { - /* export everything in the sounds::filters namespace */ - ... - } - -Compiling these files will generate the following Python extensions: -[^core.pyd], [^io.pyd] and [^filters.pyd]. - -[blurb __note__ The extension [^.pyd] is used for python extension modules, which -are just shared libraries. Using the default for your system, like [^.so] for -Unix and [^.dll] for Windows, works just as well.] - -Now, we create this directory structure for our Python package: - -[pre - sounds/ - __init__.py - core.pyd - filters.pyd - io.pyd -] - -The file [^__init__.py] is what tells Python that the directory [^sounds/] is -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] and fire up the interpreter: - - >>> import sounds.io - >>> import sounds.filters - >>> sound = sounds.io.open('file.mp3') - >>> new_sound = sounds.filters.echo(sound, 1.0) - -Nice heh? - -This is the simplest way to create hierarchies of packages, but it is not very -flexible. What if we want to add a ['pure] Python function to the filters -package, for instance, one that applies 3 filters in a sound object at once? -Sure, you can do this in C++ and export it, but why not do so in Python? You -don't have to recompile the extension modules, plus it will be easier to write -it. - -If we want this flexibility, we will have to complicate our package hierarchy a -little. First, we will have to change the name of the extension modules: - - /* file core.cpp */ - BOOST_PYTHON_MODULE(_core) - { - ... - /* export everything in the sounds::core namespace */ - } - -Note that we added an underscore to the module name. The filename will have to -be changed to [^_core.pyd] as well, and we do the same to the other extension modules. -Now, we change our package hierarchy like so: - -[pre - sounds/ - __init__.py - core/ - __init__.py - _core.pyd - filters/ - __init__.py - _filters.pyd - io/ - __init__.py - _io.pyd -] - -Note that we created a directory for each extension module, and added a -__init__.py to each one. But if we leave it that way, the user will have to -access the functions in the core module with this syntax: - - >>> import sounds.core._core - >>> sounds.core._core.foo(...) - -which is not what we want. But here enters the [^__init__.py] magic: everything -that is brought to the [^__init__.py] namespace can be accessed directly by the -user. So, all we have to do is bring the entire namespace from [^_core.pyd] -to [^core/__init__.py]. So add this line of code to [^sounds/core/__init__.py]: - - from _core import * - -We do the same for the other packages. Now the user accesses the functions and -classes in the extension modules like before: - - >>> import sounds.filters - >>> sounds.filters.echo(...) - -with the additional benefit that we can easily add pure Python functions to -any module, in a way that the user can't tell the difference between a C++ -function and a Python function. Let's add a ['pure] Python function, -[^echo_noise], to the [^filters] package. This function applies both the -[^echo] and [^noise] filters in sequence in the given [^sound] object. We -create a file named [^sounds/filters/echo_noise.py] and code our function: - - import _filters - def echo_noise(sound): - s = _filters.echo(sound) - s = _filters.noise(sound) - return s - -Next, we add this line to [^sounds/filters/__init__.py]: - - from echo_noise import echo_noise - -And that's it. The user now accesses this function like any other function -from the [^filters] package: - - >>> import sounds.filters - >>> sounds.filters.echo_noise(...) - -[page:1 Extending Wrapped Objects in Python] - -Thanks to Python's flexibility, you can easily add new methods to a class, -even after it was already created: - - >>> class C(object): pass - >>> - >>> # a regular function - >>> def C_str(self): return 'A C instance!' - >>> - >>> # now we turn it in a member function - >>> C.__str__ = C_str - >>> - >>> c = C() - >>> print c - A C instance! - >>> C_str(c) - A C instance! - -Yes, Python rox. :-) - -We can do the same with classes that were wrapped with Boost.Python. Suppose -we have a class [^point] in C++: - - class point {...}; - - BOOST_PYTHON_MODULE(_geom) - { - class_("point")...; - } - -If we are using the technique from the previous session, -[@creating_packages.html Creating Packages], we can code directly into [^geom/__init__.py]: - - from _geom import * - - # a regular function - def point_str(self): - return str((self.x, self.y)) - - # now we turn it into a member function - point.__str__ = point_str - -[*All] point instances created from C++ will also have this member function! -This technique has several advantages: - -* Cut down compile times to zero for these additional functions -* Reduce the memory footprint to virtually zero -* Minimize the need to recompile -* Rapid prototyping (you can move the code to C++ if required without changing the interface) - -You can even add a little syntactic sugar with the use of metaclasses. Let's -create a special metaclass that "injects" methods in other classes. - - # The one Boost.Python uses for all wrapped classes. - # You can use here any class exported by Boost instead of "point" - BoostPythonMetaclass = point.__class__ - - class injector(object): - class __metaclass__(BoostPythonMetaclass): - def __init__(self, name, bases, dict): - for b in bases: - if type(b) not in (self, type): - for k,v in dict.items(): - setattr(b,k,v) - return type.__init__(self, name, bases, dict) - - # inject some methods in the point foo - class more_point(injector, point): - def __repr__(self): - return 'Point(x=%s, y=%s)' % (self.x, self.y) - def foo(self): - print 'foo!' - -Now let's see how it got: - - >>> print point() - Point(x=10, y=10) - >>> point().foo() - foo! - -Another useful idea is to replace constructors with factory functions: - - _point = point - - def point(x=0, y=0): - return _point(x, y) - -In this simple case there is not much gained, but for constructurs with -many overloads and/or arguments this is often a great simplification, again -with virtually zero memory footprint and zero compile-time overhead for -the keyword support. - -[page:1 Reducing Compiling Time] - -If you have ever exported a lot of classes, you know that it takes quite a good -time to compile the Boost.Python wrappers. Plus the memory consumption can -easily become too high. If this is causing you problems, you can split the -class_ definitions in multiple files: - - /* file point.cpp */ - #include - #include - - void export_point() - { - class_("point")...; - } - - /* file triangle.cpp */ - #include - #include - - void export_triangle() - { - class_("triangle")...; - } - -Now you create a file [^main.cpp], which contains the [^BOOST_PYTHON_MODULE] -macro, and call the various export functions inside it. - - void export_point(); - void export_triangle(); - - BOOST_PYTHON_MODULE(_geom) - { - export_point(); - export_triangle(); - } - -Compiling and linking together all this files produces the same result as the -usual approach: - - #include - #include - #include - - BOOST_PYTHON_MODULE(_geom) - { - class_("point")...; - class_("triangle")...; - } - -but the memory is kept under control. - -This method is recommended too if you are developing the C++ library and -exporting it to Python at the same time: changes in a class will only demand -the compilation of a single cpp, instead of the entire wrapper code. - -[blurb __note__ If you're exporting your classes with [@../../../pyste/index.html Pyste], -take a look at the [^--multiple] option, that generates the wrappers in -various files as demonstrated here.] - -[blurb __note__ This method is useful too if you are getting the error message -['"fatal error C1204:Compiler limit:internal structure overflow"] when compiling -a large source file, as explained in the [@../../v2/faq.html#c1204 FAQ].] diff --git a/doc/tutorial/doc/reducing_compiling_time.html b/doc/tutorial/doc/reducing_compiling_time.html deleted file mode 100644 index 3839fcef..00000000 --- a/doc/tutorial/doc/reducing_compiling_time.html +++ /dev/null @@ -1,115 +0,0 @@ - - - -Reducing Compiling Time - - - - - - - - - -
- - Reducing Compiling Time -
-
- - - - - - -
-

-If you have ever exported a lot of classes, you know that it takes quite a good -time to compile the Boost.Python wrappers. Plus the memory consumption can -easily become too high. If this is causing you problems, you can split the -class_ definitions in multiple files:

-
-    /* file point.cpp */
-    #include <point.h>
-    #include <boost/python.hpp>
-
-    void export_point()
-    {
-        class_<point>("point")...;
-    }
-
-    /* file triangle.cpp */
-    #include <triangle.h>
-    #include <boost/python.hpp>
-
-    void export_triangle()
-    {
-        class_<triangle>("triangle")...;
-    }
-
-

-Now you create a file main.cpp, which contains the BOOST_PYTHON_MODULE -macro, and call the various export functions inside it.

-
-    void export_point();
-    void export_triangle();
-
-    BOOST_PYTHON_MODULE(_geom)
-    {
-        export_point();
-        export_triangle();
-    }
-
-

-Compiling and linking together all this files produces the same result as the -usual approach:

-
-    #include <boost/python.hpp>
-    #include <point.h>
-    #include <triangle.h>
-
-    BOOST_PYTHON_MODULE(_geom)
-    {
-        class_<point>("point")...;
-        class_<triangle>("triangle")...;
-    }
-
-

-but the memory is kept under control.

-

-This method is recommended too if you are developing the C++ library and -exporting it to Python at the same time: changes in a class will only demand -the compilation of a single cpp, instead of the entire wrapper code.

- - - - -
- If you're exporting your classes with -Pyste, -take a look at the --multiple option, that generates the wrappers in -various files as demonstrated here.
- - - - -
- This method is useful too if you are getting the error message -"fatal error C1204:Compiler limit:internal structure overflow" when compiling -a large source file, as explained in the -FAQ.
- - - - - - -
-
-
- - diff --git a/doc/tutorial/doc/theme/Thumbs.db b/doc/tutorial/doc/theme/Thumbs.db deleted file mode 100644 index 4b7a67255b9a09234cb92bceed18362536b58c40..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27136 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 diff --git a/doc/tutorial/doc/theme/alert.gif b/doc/tutorial/doc/theme/alert.gif deleted file mode 100644 index 270764cc58716d36f8545c07ffbccb76a3dbc7f4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 577 zcmZ?wbhEHb6krfwc*el+^5x4HFJ3%)^yuNkhj;GW`TvCB_N{CGA2IyD%W(C|x&OBr z{@-G_a_Q{m__~8F~vDYEl>qqZpDSjq@WJa>5z1Lm6Vd z86rG+L!23`^cb|27{rAb*jO1D7#RNl{|}<5jTL{gu!=AwGw6T}2E_>j`@DwarsiZ7 zvzCqy8~4s$Mnes@-VRGi5tqr$%yz7-+I%yUbrd6_%=Konm?$SD`KoeGb{17nO!DDy z>t(PKkWWZ*<cQAmnAE=fsD%$UE$ROUW+NUZ1+QQKJ-!ms2) z!wk-f=<_sLpE#kg){9r_k3+JcmI}v|3yP=3Bn5<=JQ5$B644M)RP)^A(&gG6!^Fs7 F4FJH#(p~@n diff --git a/doc/tutorial/doc/theme/arrow.gif b/doc/tutorial/doc/theme/arrow.gif deleted file mode 100644 index e33db0fb4dd85e0fe527343d95a3f28a0ebb74f9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 70 zcmZ?wbhEHb6lLIGn8?8J9}E~6W->4^DE?&OC-XFJFH7^5yH-udiOcdjJ0Y=g*&CzkdDw`}cS6-hKG+ zVdct|pFVy1_U+rhfB)XRdGq$|+aEuEeEj(F|NsB1R;~K`_wVY}tN;A@vu4ej6)RT! z{{8#cuU~7|u3fio-TL+GfByWrapT4f8#Zj(v}yC^&D*wZ+q!k@mMvR$@7{gjz=7@C zx9{A!bMM~0yLRo`vuDr#{rh+9*s*WlzC(u&9X)#V)TvV^Po6w- zyLay%Jb3Wz*|X1|Kfizf{+Tmpu3fwK^y$-^H*a3Qe*M|AXXnnHJAeNCg$oysA3uKe z>eWk^E+4<0lBLU*@T^?5dd(`K^&2*BTFEI`2zd3>o;z)v)s9R@BSUeM~|O8Wn_5q^405CHt*hl`1r~B%hzw;zdQW;{pasr zF9v2V8Hs|fgUuYmej5*MSa`TSY=y@hkBv&AY7)j-cRDt)dE zU9$D{^$pSTGkte&%f01a^!nae>+L=F4>WVj`|WA_`1r(RZF9M$J3l|aF#GrnzrDM@ zzP^$C;>NkXyT8BJIMglgzi&_FC%sFnlY$n!TsEid z)yw4z+N54FEt!_}YUPS$t6r^IvuM`A)fY$|rssS*xogRqPp5XWJpOdrfW7(58I$WZ zJ;oN#*L*&AD&X$RBj zw_mR(wCjGmkup8^+s%ySYroyf+5Yz1?SkXF-|v)M&;5S4;`!R|_iFabaxho}0O~&E Au>b%7 diff --git a/doc/tutorial/doc/theme/bkd2.gif b/doc/tutorial/doc/theme/bkd2.gif deleted file mode 100644 index b03d9ba97ca7a4c4de297b5413fd3d3df8e0fb49..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2543 zcmZ?wbhEHbWZ+<8_|5Qs zOXn|KICuX1*>mU4oIQK`%$bv?P8~mS;_#6p2M--OaPZ*2|Ns8}`}_OP@1MVZe*f|P z>$k6;zkL4q>Ertk?_a-p{qohz=P#Z=efIS6lgAGqJ-mDG?(I9bZ{E6j{l@jH*REc< zdgbz!%NH+QJb&T**>h)4pE-T<)X5VkPaHpS{OGZxhmRaScdEzI5s0g$w7;ojZHx%;{67PM$b%{MfOhM~)mmbm-u}zkmPy{{8Fc z&mZ5vfBX9N%jeIZK7Rc8;lqdb@87+B`{woQS1(__c>es^)2C0LJbCi?@#9Azd+y!6 zd*}A;TQ_gsxPJZG)vH%7U%qtl;>8OWE}TDq?(Eq!r%#_cdGf^Z(|epKfinT?$xVT&!0cPfB*i?n>VjryLRc)rPHTRA3uKl*s)_rj~+dA=+MD~ z2mk;74@!aqhZTRaFfuS)WzYdTfrE*Gf#W{|D~F87h6M+kIfS)hPHb3sxSew)=K?q1 zo*A7Y+G%$@bUlvuDjn(&P-&9#40Lqr;xS&kbj37-WTr+*jb|nb#)Z$WoGg|QnD4;E z$}7m_(UGXw(-v`R%gZ2x1SgMZtI$;@2A4Kv-JK;Wppa?5sfp?1;y3&b7cVt+vFWaj z&d7bZX)5=2y*u^=wGO|(EX?0vU(3w>&A4KNyuGc!_lP^`h5Y<|jg_As9qe9ye4b6l zwLfQ^)Ai5qX{dACwdG~H&Ag8<4?GTEepS}0bcXM2GjToHy!Q__EjE9D&${OA%e|@W z?0kFswd2>dHcxwYZtIH)da>=LulJU`xVUlQ?(e*_H|6|)aMau8C$Hs+$^PfH-TQ1R z@9Zys?=x8~Jz~zw`|IWT`TqZVsPLeHC2azu+{_n~4vNl9xsbqCE>UruSHP*_aH~Yx zjBZ);8;P!ZJ54V0s3}d$NHR8C5Yf)7bE~1dTQ989TQ>AY!NFdOXC2DM;s%c&_d8rV z$RjEy66rkABPywrb=n1o!;{1;ZZ4VZcg~QVS2QKkQ8hZvvUQqhfWosGDbqY1b%i@T zJ$0w}Ja{%+SVuX1PT{G{<#UBjZ0KRB_A~MnG4fDY!7@oii*sS?F$GVa9y2Ls-9i@! zZ=Q*62``rlo-yL)nd4^Ey?kEYDNUY&1B}f&0S6cuRaQGa$kJKA>;Eq%7X2ehueoCC=QUEHU3eC%TOvq*Tmm2XSK+O4`Jr=7U( zZ&FydBX>tq9`hr!NoRJw*|ghfxAqb3_gpz=ZgVO7Y&gikymrlj6Z;tS4>lZN(O=kf zP)lWvfi~CbhBJrxwHZGi;a@(1$w(|Y=i{-}Yc{nVm0!M~Ly3DzjuDsY>P4TJJXfqS z;xahAhV9JC3u_pJvNRTKKG*rC=8T~^^WV>g9z3~U3|A=BI!SdbC~{)rlxgI+5)z(! z=4wFv+OOB57cVqrIwsM0KykT(f*DhWazVqb?9F?>F%}%x{mz&^qo{$?RU)ZLQ|-?G zTnEFpKe1;Xw1~&~a5gKitKjT0kMrV8Gl+9w?3o?NAUHkQZs)UE{&p^m^Cy4!DX?fV zgB9nB$$h_Gtq^Xgl62Y<$HAF8L5YQtMWo33-5%j4YenS`ayE?00!e>3jw-MJ^XW8y z!ygT0hxdONnic$c44Wqe{{4ES=fL0Z4~pdvd}W;Ce@23FLHxg8uhzf+_xr>dZ0q&_ro_$*)&KXHJ~>O-SIO9zX($3d>B4+=tp z9&GGMf_)VqnxzF2~2bDEV-EKv2bxY*UR~f7&IJR9RnsyOkok(ddc;Axj;dB?G%OglF%;MDPOi~D?QUFpVyv9A|h z-}B@si`tq7#+)DGNi!KXG;qF2@a}kXP|7V*RfR{=E8>Wf#<827wLZzxk8fxNZDLf5S`-*g1G-<_FP%4WjK(VO8e9VOK_kzu*20`H0i zw>bMIw5_uIp5=Zas$^%`)?kUpBJDfY-Q3o_ZSzvy++yzhJ8!O;Gs_&hbMvQ zpya!~X&!SPDP7<3OK2fW|KgaZUKcD+PhC_zpZV^KHUle0VT;nG$+E9cIWPsC>0@x( zAlp)Yd^eZyf%0RAKYZvbPkf-tUnv)NPh-JxnnTmUv3TtYXDw-J(~ak diff --git a/doc/tutorial/doc/theme/bulb.gif b/doc/tutorial/doc/theme/bulb.gif deleted file mode 100644 index 74f3baac42f12ac0551040a00f78cb573360a0ad..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 944 zcmZ?wbhEHbU2JX=yWO8qb`WHgo38Gifu=q@6jF_W#UGhBGsb&&*6a zGjrydnP<+-{D0;Q!i=IrIPje+GvC495Q% z(*85d1W7Xd|8LCj-`M!SaoT_5nIN^s|No~k{7*CfpO*GNZ6-)-+W-GE8UD{S{y#JA z|IC>nlV<+^e}>`z8RP$8cYq8A8~y)3Nb~>yAnE^L0P?^n9t{C$ zm!W3VRz=HX0SO5P1_s5SEQ|~c3=BFT0%V2*i>ts1&-4h1-QU}6JQPJ#9Az#qP{_IL z>m8xcQ#>ccK&B>uvC-M7@I$1?63NFG4AfGLn>kr6)<~>7uC&oZb>E%VNA7Gc3=Gx) DZ>u*X diff --git a/doc/tutorial/doc/theme/c++boost.gif b/doc/tutorial/doc/theme/c++boost.gif deleted file mode 100644 index 58be431a3fafbd5adfa01e829ce8d80a03a83ed0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8819 zcmZ?wbhEHb6lDx!_|CwzZQFbH(K6ngWKJ ziiVnsJ(`+|nwo~1nogRU#hRMcnwmYDhC!N^Q#37?YC7%JbULQ#bxbqrnr8BQL(ODE zLoY+8V}?P;41=y2MlCgrx@H*l+%Wl?Ve)gs?C+L}mX?N=mWDx=hSipqQ!JgPSURn> z^vbpjT56g6-Lm?-WzTmf!(=DJY9}WzC#NVUr)(#u7ALR0PC?a9L35m__ikjmUwbv`^m{;;Wuj=n!J>P?zs)M|u zg1oYWg0h2x<^%<;4T`!KlsqLUd1+Ac+Mw)XLD|=WvhM|DKM$(D7F7K{sO5W5&-0+3 z??H3EM|mYj1#OK2ftIN3wNcggqSpRT4$4lBTAG}kot#{qoIE8tyC*q&PIC6vOS7xD zW>??KZaJ6Tb1u8*UUtv(>?z-~m%h(F_CNdD|Kj4M#l`1}=X@_-`@MMU_u_NktBZT8 zpp&i(JHp3~FQ z(gOl>dV03@^c?G%^1f%zxt=-KdX`@6S^B(Z>-#A^bEeFhGiA=&DRcHtS^9j+()UxA zexI`S-juEHr|f+`W$$+oI`@ChoO5&5URye6?b11Wmo7cFbm_UJOYbdRyLai)y3n&#m2hZSB_QYmePqd+hz%bMM!l`@Z(t_qETz@7;S2jPC8- z`+V=-_j~t#-+S!X-gEc%o_oLd-1lQ!uN`~-{oJ{G=gz%9ckkZ0d+*QP`+n{H_iNw3 z-@Etx-o5Y7LE!uQ=ilFd2LZ*OEQ|~c{~2^ZSpk$M7&!hh{O6SM*s$PWGl#HN%!v&P z54Q^_d(H9KxaerNgmKoL6B`#F?^kf{lJVTM)Z?TNcv$a| zX8p~bZNB0Df&T~6_*U;Ue!k)Nx4)0STN=lnoy=Uk&wHlPgHtoufA^>{GB7Z*NC+qx zEcpIN;8}uG+nxy)Z*Fk5pN`YwZ+XkW@@A=`LV`o-eI~Cj)^QWQ-oG;S@4wD($Mp*; zKP`6s{@DHBpR&r|f1Y;l*S~LH`{mvB-SzM1@2UKMVR3)O&lAhfXRyDTtWf>OAmU!t zs=u54Gam$&%`7~<@(I8EdENsIoYf18T1uH!F5G5d%-B3PRcBIqc*K(2v|IK+EpEtF zvVWTFZ*Tf*@q*YTCzbu}KZ#iM+uB`wtUT%073U>3|4u$WZ{ub)vwzYj1 zuldQd;&D~NvF-O#<}b8Nu8>@&;-9;Xcf)NZMy&}m=Ir4$;7VZmncQc2tKjgwqRO9N zm2B@69PXQ`ze#LXi_kW+n@esNs@-bIFpJ8}njN-lZftLp)yfr%lw4wFt350_kh}L| z+bR2hhkXvb%G=Y~cylrH%;s)`%pM)00cDHCB8v?zgnNb(GKA z#VV6;>)Rcd&s%@~^7x$1zd6b0?C$^iIo0ykHf4VM&pV8lZu@Lu*+1oT!|Hxpf4|Hp zebJ9zByaeB$KplThPhp@+}w7ws^{-I@aj&~7QP3E9IP%KooDK%P!P@VoTuVR?H94` zCpNd97&Ruj`*iYECj5P=JLyHiW`FayIluYr-`yzgH@o}hbD!0}CB}K?FTZT=v;Hk} z*Wb!~J9CMZ>G{tyuKeBLtiR*imCgMV{z~j#(jUWiC!yMCQ>B4B)0tJb8Fs#D?q0)q z;wM8smqL1^eT~I-iGN!rN2$G9{?}&G>8NXw2Oq>Pd~2*xz3{8?!x??n>n!ZQoBUAi z{}dgt z+CLsYPp}lKr}0kz_UE(Cjeixn=arWW*d5?Mdt3Fq+0Tf_yms$*G@rM4{ATfKgFi9M z=WOo^IQyI4zjJt>-Hn*T{Dw!KeD?kQBBq$%>gJQnz2<*jxcxrVXp+6cL-y^1<5sr{ z`AbdC%KXfjzPTZlzxu=CroTTf_WNC*B_^p;##iY5_F7rj>MP4aUq9$&K4+pK&+5n2 z!p(61TN3}pH%Ikq4zMyjF=2>~Y^(eCN8^~qA4a>{2K|ohC)^DWE#y!Acv#~4jpK$J zCh})UD9aza;A&SA$Xgq+QGWk|V|EKZcGtx$mio(a-29VaPu`tm*#{5Wr7lO9EI*qg z_x*>M{f@2fH8&SWOYE86f26Jd%#L$;3OOAdnOkRvpM0FMR_TBQhXG^Do5zBR5#60P z3bl5BIiCOT1+(6&VC{gj>ONC~C-i-q$Y1rM!|PW<>cn?T7pPrjwogoYI#uL~SMtlp zaz72i*j_HQ;AZM7j}w0CS{L;d zE~=m2vY1ct#=_Edu3C*3-sHVm(ags>fq^Mvq3pkZi{15F7V;NbD9dljIA%L#VNZ?D zV~H;}T(zDsa>iYGEV_O}yH-sgfBYUL`Bfc9ZFVf`kKOQS;hGc2^^z94q+D?pUozvk ze$T@GEC*-#>lH7}HwE_RS2WAr?r^g^wz03K#aZ@e#Bu9)AN$IGtZA#CBQ$x2iWPrW zvErQ=2W3_xMpmB(tM~#K=CTy=7u!5q-M^w)P^e6{jAyY(LaKY+pCi4wHck9VM_a$F zDG1wO*Cc%*fz5u(MV@MfWU1bpDlCu?UGugvkfU^sbp!| zxOzv6ZNkE?@*_%%jzze-_CD;3w@H>;ccIm0Rb%h%u*ci(Z)i6^RM?-tM_K;8hr-oY zM{UCTjyY-SaTHfRKD#%8%}iBUm67MdoiIZO^B$E338V5&x1MTFTCr?uCx;-H%JxUH z3mjamCnU1wGCUG~f1;7^%*8gxEy=u@8SPS66#7l>D9UDfd=vCC=+|Ac@aFuEb=*%9 zIm~Y?=AByMuBv0$e{@&!#tE^l)*+1Cl?xt;e2G};70%6*af4afD0ja3m4*E!OAgE5 z`6Sq&=A-;I!Rqqtvb-Xeq}~{nV=n90@#$AEa?1%Um{(T8W~i0E{Pl+oR>vIJbpBNZ zobUd>K=y9M@!IZReAOL?r4CPUtG%1ZS6F#C^R0us^@4AG_H!T0-2HKF{+)|`WhL+Z zZ%%Trf8MB5S+Ke~X!Z1l=NA(c6<5oCom90~-l(`LsX7Qzz_eLm>(Kl$h$PuI8) zit=SQw(GCB@s7b^!d0#lnQ}Hi99fkXH0=A|X!GNRb(OV21Bb-|^Vbg=IkYA;?BjP} zOgpjFT3{ka%=JgI3K@>(c7c@^42{wjKbowTENIR1P~?44&?L2MBdhL`IPPZ}i~{!< z+Y{eA@V@tOmcDn9&1OfkKwE~pVpBh-&z5GP=@$RAE(CH0Z%GyrOl{S9c91Li%wtKN zSU2-m{{$~rH$0ZEebc_^SL1`3yjeZ_&hE!-krc^Hi0k5 zfc3=%wjhC)tOtBYukkfIaO_D>ou0ti^_A=G0rm+O_>O;wIPih%^Ma^P2|W7^_&-kO zzgl4DdNuUz0vm=;hF=5Z3^ytHx0Z2z=dYb$c3#lD=7MLLBbWLX2BrgiiA?hPpEP5G zEWbE#EiaH(GGO=@e68ro2V>W*eBBi$uP*R1ec`>ff%j-a@Vy4UD+_pUU*LT(f$#PK zW2Ps(4=(V|?cn?WneTQ(*8>5*mkWwtEr?#9!S{;6l#j*KD!hcFh3`cI--#r?oipP9 zhVuVNjTaR0`N1T1ghgyVla}7KHUVM7tmpiy3DVmO)rBwk{X0;0c(ETx0&kfj-%108 z9|!oEGWvc981y%A2^ceQ8}KhI$nJ1xENb9*#K6Aj0-yH<#`_BFodfceGS$i1-_sS zY^S!dEi>nMaDc73fv>{hALm;Kj)@6;(>8FtNZ^{Tz`yzf=Vyn=Pan8DTX|Pc<$ZX- z?e+%#^)L7zFz9_vM z_8@^H^8w!!2aY!h98(MUY7$asU*%iL(7N#e_m>CUt3~-P9B@k#;VW!$xR<2=jmhS@ z#s|b=djli_8U=dYS(jurVFrU0lR}V3OrC3*TQKIBGXIrx@5i+%WI^ zVz&nkyr&I;v z0VMg!CJfaUiT*z>p;lt1tWCotY|UaQU=v)x6(_*H-(kYT3#=KhSe-8LIu$TqH(*gaz{@&;fvuD2 zUIU|s0AHa2>IQysDU<(UdLJJt z2^quLYa;mVo<-}ljZjS%Wn$&^PTy>D40HT z;OY6mp0=Qj=b`T230#{#aNiK%`x?n}@dMA52HyJ&yeAoWuNf@3Zm|7+K-V<~o{I&% z_Y&scci_G9p_Yw{PvVz-lefvPQu`MZ_~v);y;@KlaG9^3Nn_8B1+z3dUoh}LGf4b= zK{fG{Wg3&%xfea@&8wLe8FLiXc@)&c0=VuZ^s*GN**VDW6p(A(()&iRVTbh^rW0jP z7&u-8#JpX=Y}vrq&cJoSfLq`rU)}@O6Aer68?ZPF@H#(WJ*L1C_pgALCxGFC1Czl7 z9Tp>J@FH2$OfJ&0kVI$Zj~v;J(l!^Q`3hK^x}|>^FtIo=1_|wA?%17iQtqjN!s#eJ!6{sy8<;~s z@GTVJ+F!sU_>s@4fF~=8=T#JsvjF=A1s10U-dG04{R|9jA9&jv*lsH@NEECvy}%oI zfa!VxvmXO5ivjcX35=2#cqJDw-8En~e88*C!KZX`X7mSMKLytJ46KkTg##f!d za)BWsTq*JA1Kz0tk$W$2|6^LoPB zpPmbjZs5K0V8NXa_In+8I1CrO{E%SE%~R!v|B0im`Z;U?7n0ZldCCnqCqL!>b%A^T2L8k?_E#S8 zKWtE$V6D2aI8*17$dYV<35|TJA5QKP%;t1pteL=fw_%H}$eQOndS#cgzkR?laRJ|s zKYUgREUzYTF8si^R)Kwg!yfjD{3j>auqU!zSiRo)1J`A3mrq~$*sC}uF)#>z;FfY= zy;8s&yMa6K!>tny@!uTypCxbwC2&bCU^*YbEZM;KX*c&Ob%*|IdUrN(MK9o5tIivB zfMs`sz{&-zo&VNyi9h8&e}MmL0PnlW*QTiHrB%rD2`Sz&l=w4&yZ!;w-o!O(MJ(P2 zcq&VX9M=R3;3EB@aT!N zy>(#8{J^(Jpz-q$?zIg9KN>g!8U&tNv1~SAneXtJO_5(FflESxWxoLH>staF6S(vR zn0E; zD8*U$_%5SYW?)|9z`E&!z`7U>Ej)&uzoT&Iue(4Eo<2{8*p&xln+EBa!p*E-sEjR`CXb%?}vs9C+CS zc>)uTuzlq7ci>=8Thc|+W?27z4P~9K@Lgrrf@$`#({Ab*|TdmIDGqG%b)WqLkGG!L|KXgd_70Q?5T2mRp`*D&_ z@>F)I_nJZone%$HqnzpI921zQ4MoZiUy&->kjyTeJV| zTl#tWxx4!-KmWUW`n$jU{`$WX)^m1*d`dYr$u(`s^!H0nPWcyB_3s;xZv39q4|2Yn zzIRTtt=oO3^XI2^qAMyp9ril6WW+9t+TWzR^|)5woQR@53of5f?mJer=v>B$EM~_)l-R_Xznf6oeWzx^n@>{b0t*hncskrx`GWF}r z-|h43q`F^hI>qN=;Mgm6>y1iBT+#~J;wKZA&pmWUafK}B!N}*b1@|J^Wr_|7w$I7; zt5KV}^pB%DuT#X%Ba`w>PAPHs?y^)Ccrj^$o3iz~1@6k_#~hL;IaoQWPL1ul_;lu{ zd7ka_DnIRXpI@`?j=RHgxvCG2C$tuwa9};IQtaBT_j&o;vmXvFpI;sK>Wy4gRpURF zx#205?9-~>M5gqWe4B7|UVww7`icU(lge|7P6fL1pPHrU!e_baA_te>nnx^adgfI& zUFu2t;4IO%i<70n&+o%San%|HedVl@6;AWKk6m2OZ}%zks6=&KWt)7)yp89V<}rA? z%N=?ZsAE_s(VU@Vc)DeqPn#Fh=Y?f+?)J=|a&OOb@#2z)uJgQ7UK-5HJ1}Fhbfk-? zx?toX&Zoi!4wf!~hH8aNHihh&z`V2P-HKLA*LkNoW{EF3<-zG*_Tq$mkkrS6?RfzK zi)L)yccO7#VcNpweXhSMTc_5Ay!<*n>&MRZ^Y{M=JbvTQzmx0^+S0ev7cnkAYI%$4 ze2dSLdDs87w98g~n;5K6|7u~oT;-0<%jK%?RsMQewIFZ#Y*o`q%h}b9U#az)Y&)jG ztzi=NtjBP{?j)(+u9hXCeLp;pPS0B4c=VC){E6*ywHj~S?z!k$Bxs?Ch6K*n1cHi^2SLRI6N2b>kxI`y4o zyWWeBTnRUvB^xKXGX6{a$XVU+PByH-#VCbwxAUDuqyj`)%|(fb0UMCF;o@~$nC z4L=wc)LnVw{jOQbFz{ZQmDd6De@%cIkli+R?R2an})b{&`e_^_|6 zhFMB#rMr~Q3PC3yrgDjov)uMA?DEKHkxt&w<`xpzn_8nRxoQT>CkrF~*d>SZBo?w+ z?Fu|n7o#a3d8^%N%MyVOlO^eaEKg@}Jz1*eH&N-wg5$s5IPz3^D9ii_U^98v*mIiE zS@N5rtL=>~-sj(J>X{(W>-OiLW1oQ0av7aH9ty{%P0aRKC}b|x_}PG|CH_kT`~C+9 z`P3Ra+|!P*r!d@h-KEH8@F7`r^#gVlzk~em{xU@zUEyzjL2zHmpT(*FBce7jg=|i1 zy)<9)rq6VbLlX>2k11Z*;AXc+u&=u2vBZlV$DWog>^5mSEI0S{QvHvD{jvX;L=WY- z8ya6SNr^fl^rS)7*hR}Pf=5l+@4;2$GmgFaC5t5%XS5_532_J?xS(`-gOmKW<6X6H z4vGEKXfu4~%v&GQyzf&m*TY){h!&qb{Ur2BZ`q(`y zc8OfiiEy_r#m+-sDN^@09JiIawAI;rj^bTUw$0(J=ZP#j)z%h&day9b}a6P@?2ydR3y8pG#d0= zVV2oj5oW$XaLI&*$KpLZIqan_HqDN0>Ak7Tro88b+P@1|ZWs$6JnnKue8F*D?b=?) zjkV6wYB_JG7cyo|*fwR4d8Nn_h0HhaqUXA~?P_}5C;rksq}8)0KIJ=4+JzJPlRk34 z=(@}kzV1Xqec{?8jE8tS4{{_P&J@fPVV2ELnm^%d%*=L=C0k;IUJJfF$p7xk_T8;{ z?5&qR^3`zcxcKNoj_s?1x25)r%G59Av2~epH+{kOBh%FiAJtt<>Yj1<)UmG3mJF|W z3j&;#e=T4$eDYCEM!4@p^|7z+Wnn4pZ=B`+bDIhs zp272;Y;n*2 z{OG1NpCiA|f7$s7FOOf4TN2r3^2Gk%3L)nw3;WMV&Aw5swezu!b8fc&Qdu$ATh=W1 z9_H;>oVn&L+Z^jlyk{;Yue#b^`%opU3=oSpr%~ki<~5JQji;JxWPB4V%(6NB`TUQo#$ArQu`m89 zeQ3(G-2NtTYo5ba*_RpZDk}wZJ=J^VoEE!V?K14W$R8;8a>8Ggw;PMvJUr#@EjVVf zB9ZR_^M2{uAKa|JCcG~{Wm5rX_ww!QeeOTV*8nj z4)0si4<@UW7_dKEJVDoK50hrcAq^$2os;Tr?Rc+z@O$F?qcc0Sx_ah2>Rxu*Io-p) zEuv>r&_T99&dIwc{lCDIa9F6NfT!+&%9=$2-<^5Z-fDko&GE;oLv@Ra&c`)+H`o99 zwWdt_pq5I$u!s(4S++p>L(}xgX;slO(kd%dpQv=KP-;D)!WihRZ0-D~NT9xB{@Dz3 zlb3edTMm~OJKH@LGJJA)O}3$!%7hiW4?C(HaWXmL>~h2<Q%P5$_{Me6AeveR9N4XL17rgEatT*T~8M diff --git a/doc/tutorial/doc/theme/jam.png b/doc/tutorial/doc/theme/jam.png deleted file mode 100644 index 224ed7914bb5a31a407511093500aa1fe9d9e571..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3884 zcmeAS@N?(olHy`uVBq!ia0y~yV5nzcU~uJNV_;xNjW#hE=bLrwBlWk7u9BNWG%WIzG^?ia{Jx0?d2cu65lo_tIq4R{ZpB|^Gj6) zSQHbUotHf@zxm;v$tNPW%s1Luc2<|6?FW0^VrZqF7Q%Y`1Ew|lr=xYj$EHQEz3mDMmMpd z>ejiX)97pynn`5kW z|CRi$_`uF-U0Tl!|N5S1TOOPDXU~o+TYOinI`YoqQ_`=^1)VOOpVS2UPMZHtf92(U zF(~lpmyJ~=b>FwfdM6w>w@64vPjkD9T!BlS8{-PeFW+C~FR$XwJ;(0LL4_y0b2(bBrxt6b;~fkM&QareVtIlX>mx{c)k=f}URyJiaR zcRjOF;pM%D1^TaQcvl$+gnzii-F1xrciDrp+t{xBlnQwM`lzw)`c>DOBDhY4PWZnt zR)FQek=PkocKsFVcH$fQ_AtJdIN(>n{=t*q-~sQq@h3+fzfG`F{L=O>KV|n{Gpl%-%i!=JgyXArJMZ($hYaT!{XP6Jj;Fo) z|Aw2nSEX5*73

m`0On#VPL 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 diff --git a/doc/tutorial/doc/theme/note.gif b/doc/tutorial/doc/theme/note.gif deleted file mode 100644 index bd92f07555d06e0744b408acc0fbf463e280f2f4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 151 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 U=h+`HFfcH9y85}Sb4q9e0E&RLWB>pF diff --git a/doc/tutorial/doc/theme/r_arr.gif b/doc/tutorial/doc/theme/r_arr.gif deleted file mode 100644 index 2dcdad117debc34257b746cbe843bf5ca8737b59..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 147 zcmZ?wbhEHb6k!l%*vtR|#>U2JX=yWO&OCGG%>OfK|If_)4`TfP|DWOif8+oE)BgXT z`Tzf!|NsBLfB#&gTE>G6muSe93zS-%fd>Q)&EUbx3v}%NcRk;>%V0Cvz}Z0{|MoM2G+Y diff --git a/doc/tutorial/doc/theme/r_arr_disabled.gif b/doc/tutorial/doc/theme/r_arr_disabled.gif deleted file mode 100644 index 2100f78bf35a47e09ca76ffcc6e80c5a2b11e359..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 91 zcmZ?wbhEHb6k!l%n8?5|bLPzZ_wWDz|DS<@LGdRGs|W)VgAM}&0|Q8&fk|gd|H|rv v@(cz3o}Svfg4O3$GVLgQHgm3)*?|1&XIvGFi0itr1TiFoeP&p1C|3gi5M|Dy8)Dq>pVFYM_y+=U^T ztHBMdj+tQ(A2Y*wF$RYE_4D-@jtU##9xMTW{_9v6c`wK7#J8B1sE6<80-`n z7><}aTg5mA1O&%;g!uX}*f26MGK54pa~u~3ne&L_xcGT71qKC%`|QWX?G$<#K=P%G z=f$!jvLf=G=8H2hFfyd8*(n?_D`m7(uv4gs=yaGbo~{-bxlJUa@tDY4zP5<9g6(Q8 z@$VV#2iy??g*_vVXy`OS*Qv? diff --git a/doc/tutorial/doc/theme/style.css b/doc/tutorial/doc/theme/style.css deleted file mode 100644 index 53a6205e..00000000 --- a/doc/tutorial/doc/theme/style.css +++ /dev/null @@ -1,170 +0,0 @@ -body -{ - background-image: url(bkd.gif); - background-color: #FFFFFF; - margin: 1em 2em 1em 2em; -} - -h1 { font-family: Verdana, Arial, Helvetica, sans-serif; font-weight: bold; text-align: left; } -h2 { font: 140% sans-serif; font-weight: bold; text-align: left; } -h3 { font: 120% sans-serif; font-weight: bold; text-align: left; } -h4 { font: bold 100% sans-serif; font-weight: bold; text-align: left; } -h5 { font: italic 100% sans-serif; font-weight: bold; text-align: left; } -h6 { font: small-caps 100% sans-serif; font-weight: bold; text-align: left; } - -pre -{ - border-top: gray 1pt solid; - border-right: gray 1pt solid; - border-left: gray 1pt solid; - border-bottom: gray 1pt solid; - - padding-top: 2pt; - padding-right: 2pt; - padding-left: 2pt; - padding-bottom: 2pt; - - display: block; - font-family: "courier new", courier, mono; - background-color: #eeeeee; font-size: small -} - -code -{ - font-family: "Courier New", Courier, mono; - font-size: small -} - -tt -{ - display: inline; - font-family: "Courier New", Courier, mono; - color: #000099; - font-size: small -} - -p -{ - text-align: justify; - font-family: Georgia, "Times New Roman", Times, serif -} - -ul -{ - list-style-image: url(bullet.gif); - font-family: Georgia, "Times New Roman", Times, serif -} - -ol -{ - font-family: Georgia, "Times New Roman", Times, serif -} - -a -{ - font-weight: bold; - color: #003366; - text-decoration: none; -} - -a:hover { color: #8080FF; } - -.literal { color: #666666; font-style: italic} -.keyword { color: #000099} -.identifier {} -.comment { font-style: italic; color: #990000} -.special { color: #800040} -.preprocessor { color: #FF0000} -.string { font-style: italic; color: #666666} -.copyright { color: #666666; font-size: small} -.white_bkd { background-color: #FFFFFF} -.dk_grey_bkd { background-color: #999999} -.quotes { color: #666666; font-style: italic; font-weight: bold} - -.note_box -{ - display: block; - - border-top: gray 1pt solid; - border-right: gray 1pt solid; - border-left: gray 1pt solid; - border-bottom: gray 1pt solid; - - padding-right: 12pt; - padding-left: 12pt; - padding-bottom: 12pt; - padding-top: 12pt; - - font-family: Arial, Helvetica, sans-serif; - background-color: #E2E9EF; - font-size: small; text-align: justify -} - -.table_title -{ - background-color: #648CCA; - - font-family: Verdana, Arial, Helvetica, sans-serif; color: #FFFFFF; - font-weight: bold -; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 4px -} - -.table_cells -{ - background-color: #E2E9EF; - - font-family: Geneva, Arial, Helvetica, san-serif; - font-size: small -; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 4px -} - -.toc -{ - DISPLAY: block; - background-color: #E2E9EF - font-family: Arial, Helvetica, sans-serif; - - border-top: gray 1pt solid; - border-left: gray 1pt solid; - border-bottom: gray 1pt solid; - border-right: gray 1pt solid; - - padding-top: 24pt; - padding-right: 24pt; - padding-left: 24pt; - padding-bottom: 24pt; -} - -.toc_title -{ - background-color: #648CCA; - padding-top: 4px; - padding-right: 4px; - padding-bottom: 4px; - padding-left: 4px; - font-family: Geneva, Arial, Helvetica, san-serif; - color: #FFFFFF; - font-weight: bold -} - -.toc_cells -{ - background-color: #E2E9EF; - padding-top: 4px; - padding-right: 4px; - padding-bottom: 4px; - padding-left: 4px; - font-family: Geneva, Arial, Helvetica, san-serif; - font-size: small -} - -div.logo -{ - float: right; -} - -.toc_cells_L0 { background-color: #E2E9EF; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 4px; font-family: Geneva, Arial, Helvetica, san-serif; font-size: small } -.toc_cells_L1 { background-color: #E2E9EF; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 44px; font-family: Geneva, Arial, Helvetica, san-serif; font-size: small } -.toc_cells_L2 { background-color: #E2E9EF; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 88px; font-family: Geneva, Arial, Helvetica, san-serif; font-size: small } -.toc_cells_L3 { background-color: #E2E9EF; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 122px; font-family: Geneva, Arial, Helvetica, san-serif; font-size: small } -.toc_cells_L4 { background-color: #E2E9EF; padding-top: 4px; padding-right: 4px; padding-bottom: 4px; padding-left: 166px; font-family: Geneva, Arial, Helvetica, san-serif; font-size: small } diff --git a/doc/tutorial/doc/theme/u_arr.gif b/doc/tutorial/doc/theme/u_arr.gif deleted file mode 100644 index ada3d6e043d2e4314a20d6783f2800f2f21d89c9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 170 zcmZ?wbhEHb6k!l%*vtR|#>U2JX=yWO&OCGG%>OfK|If_)4`TfP|DWOif8+oE)BgXT z`Tzf!|NsBLfB#pCE@bTiY5O-A{7vV42g%c7%l^E8u0x - - -Using the interpreter - - - - - - - - - - -
- - Using the interpreter -
-
- - - - - - -
-

-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 - -by hand. This is -messy and especially hard to get right in the presence of C++ exceptions. -Fortunately Boost.Python provides the -handle and - -object class templates to automate the process.

-

Reference-counting handles and objects

-There are two ways in which a function in the Python/C API can return a -PyObject*: as a borrowed reference or as a new reference. Which of -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 - -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:

-
-    object main_module((
-        handle<>(borrowed(PyImport_AddModule("__main__")))));
-
-    object main_namespace = main_module.attr("__dict__");
-
-

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

- - - - -
- Handle is a class template, so why haven't we been using any template parameters?
-
-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>. -
-

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

- - - -
-Start symbols
-Py_eval_inputfor interpreting isolated expressions
-Py_file_inputfor interpreting sequences of statements
-Py_single_inputfor 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:

-
-    object main_module((
-        handle<>(borrowed(PyImport_AddModule("__main__")))));
-
-    object main_namespace = main_module.attr("__dict__");
-
-    handle<> ignored((PyRun_String(
-
-        "hello = file('hello.txt', 'w')\n"
-        "hello.write('Hello world!')\n"
-        "hello.close()"
-
-      , Py_file_input
-      , main_namespace.ptr()
-      , main_namespace.ptr())
-    ));
-
-

-Because the Python/C API doesn't know anything about objects, we used -the object's ptr member function to retrieve the PyObject*.

-

-This should create a file called 'hello.txt' in the current directory -containing a phrase that is well-known in programming circles.

-

- 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 handles.

-

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

-
-    object main_module((
-         handle<>(borrowed(PyImport_AddModule("__main__")))));
-
-    object main_namespace = main_module.attr("__dict__");
-
-    handle<> ignored((PyRun_String(
-
-        "result = 5 ** 2"
-
-        , Py_file_input
-        , main_namespace.ptr()
-        , main_namespace.ptr())
-    ));
-
-    int five_squared = extract<int>(main_namespace["result"]);
-
-

-Here we create a dictionary object for the __main__ module's namespace. -Then we assign 5 squared to the result variable and read this variable from -the dictionary. Another way to achieve the same result is to let - -PyRun_String return the result directly with -Py_eval_input:

-
-    object result((handle<>(
-        PyRun_String("5 ** 2"
-            , Py_eval_input
-            , main_namespace.ptr()
-            , main_namespace.ptr()))
-    ));
-
-    int five_squared = extract<int>(result);
-
-

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

-

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 -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<int>(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 -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:

-
-    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 -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 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
-
- - - - - - -
-
-
- - diff --git a/doc/tutorial/doc/virtual_functions_with_default_implementations.html b/doc/tutorial/doc/virtual_functions_with_default_implementations.html deleted file mode 100644 index c1d28c33..00000000 --- a/doc/tutorial/doc/virtual_functions_with_default_implementations.html +++ /dev/null @@ -1,122 +0,0 @@ - - - -Virtual Functions with Default Implementations - - - - - - - - - - -
- - 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:

-
-    struct Base
-    {
-        virtual int f() = 0;
-    };
-
-

-had a pure virtual function f. If, however, its member function f was -not declared as pure virtual:

-
-    struct 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
-    {
-        BaseWrap(PyObject* self_)
-            : self(self_) {}
-        int f() { return call_method<int>(self, "f"); }
-        int default_f() { return Base::f(); } // <<=== ***ADDED***
-        PyObject* self;
-    };
-
-

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

-
-    class_<Base, BaseWrap, 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.

-

-In Python, the results would be as expected:

-
-    >>> base = Base()
-    >>> class Derived(Base):
-    ...     def f(self):
-    ...         return 42
-    ...
-    >>> derived = Derived()
-
-

-Calling base.f():

-
-    >>> base.f()
-    0
-
-

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