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 4b7a6725..00000000 Binary files a/doc/tutorial/doc/theme/Thumbs.db and /dev/null differ diff --git a/doc/tutorial/doc/theme/alert.gif b/doc/tutorial/doc/theme/alert.gif deleted file mode 100644 index 270764cc..00000000 Binary files a/doc/tutorial/doc/theme/alert.gif and /dev/null differ diff --git a/doc/tutorial/doc/theme/arrow.gif b/doc/tutorial/doc/theme/arrow.gif deleted file mode 100644 index e33db0fb..00000000 Binary files a/doc/tutorial/doc/theme/arrow.gif and /dev/null differ diff --git a/doc/tutorial/doc/theme/bkd.gif b/doc/tutorial/doc/theme/bkd.gif deleted file mode 100644 index dcabcb80..00000000 Binary files a/doc/tutorial/doc/theme/bkd.gif and /dev/null differ diff --git a/doc/tutorial/doc/theme/bkd2.gif b/doc/tutorial/doc/theme/bkd2.gif deleted file mode 100644 index b03d9ba9..00000000 Binary files a/doc/tutorial/doc/theme/bkd2.gif and /dev/null differ diff --git a/doc/tutorial/doc/theme/bulb.gif b/doc/tutorial/doc/theme/bulb.gif deleted file mode 100644 index 74f3baac..00000000 Binary files a/doc/tutorial/doc/theme/bulb.gif and /dev/null differ diff --git a/doc/tutorial/doc/theme/bullet.gif b/doc/tutorial/doc/theme/bullet.gif deleted file mode 100644 index da787e2e..00000000 Binary files a/doc/tutorial/doc/theme/bullet.gif and /dev/null differ diff --git a/doc/tutorial/doc/theme/c++boost.gif b/doc/tutorial/doc/theme/c++boost.gif deleted file mode 100644 index 58be431a..00000000 Binary files a/doc/tutorial/doc/theme/c++boost.gif and /dev/null differ diff --git a/doc/tutorial/doc/theme/jam.png b/doc/tutorial/doc/theme/jam.png deleted file mode 100644 index 224ed791..00000000 Binary files a/doc/tutorial/doc/theme/jam.png and /dev/null differ diff --git a/doc/tutorial/doc/theme/l_arr.gif b/doc/tutorial/doc/theme/l_arr.gif deleted file mode 100644 index 5b3cb1cb..00000000 Binary files a/doc/tutorial/doc/theme/l_arr.gif and /dev/null differ diff --git a/doc/tutorial/doc/theme/l_arr_disabled.gif b/doc/tutorial/doc/theme/l_arr_disabled.gif deleted file mode 100644 index ed58a605..00000000 Binary files a/doc/tutorial/doc/theme/l_arr_disabled.gif and /dev/null differ diff --git a/doc/tutorial/doc/theme/lens.gif b/doc/tutorial/doc/theme/lens.gif deleted file mode 100644 index c7901819..00000000 Binary files a/doc/tutorial/doc/theme/lens.gif and /dev/null differ diff --git a/doc/tutorial/doc/theme/note.gif b/doc/tutorial/doc/theme/note.gif deleted file mode 100644 index bd92f075..00000000 Binary files a/doc/tutorial/doc/theme/note.gif and /dev/null differ diff --git a/doc/tutorial/doc/theme/python.png b/doc/tutorial/doc/theme/python.png deleted file mode 100644 index cc2ff1d5..00000000 Binary files a/doc/tutorial/doc/theme/python.png and /dev/null differ diff --git a/doc/tutorial/doc/theme/r_arr.gif b/doc/tutorial/doc/theme/r_arr.gif deleted file mode 100644 index 2dcdad11..00000000 Binary files a/doc/tutorial/doc/theme/r_arr.gif and /dev/null differ 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 2100f78b..00000000 Binary files a/doc/tutorial/doc/theme/r_arr_disabled.gif and /dev/null differ diff --git a/doc/tutorial/doc/theme/smiley.gif b/doc/tutorial/doc/theme/smiley.gif deleted file mode 100644 index 4c848f8f..00000000 Binary files a/doc/tutorial/doc/theme/smiley.gif and /dev/null differ 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 ada3d6e0..00000000 Binary files a/doc/tutorial/doc/theme/u_arr.gif and /dev/null differ diff --git a/doc/tutorial/doc/using_the_interpreter.html b/doc/tutorial/doc/using_the_interpreter.html deleted file mode 100644 index e39e8899..00000000 --- a/doc/tutorial/doc/using_the_interpreter.html +++ /dev/null @@ -1,270 +0,0 @@ - - - -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
-
- - - - - - -
-
-
- -