| [library python |
| [version 2.0] |
| [authors [de Guzman, Joel], [Abrahams, David]] |
| [copyright 2002 2003 2004 2005 Joel de Guzman, David Abrahams] |
| [category inter-language support] |
| [purpose |
| Reflects C++ classes and functions into Python |
| ] |
| [license |
| Distributed under the Boost Software License, Version 1.0. |
| (See accompanying file LICENSE_1_0.txt or copy at |
| <ulink url="http://www.boost.org/LICENSE_1_0.txt"> |
| http://www.boost.org/LICENSE_1_0.txt |
| </ulink>) |
| ] |
| ] |
| |
| [/ QuickBook Document version 0.9 ] |
| |
| [def __note__ [$images/note.png]] |
| [def __alert__ [$images/alert.png]] |
| [def __tip__ [$images/tip.png]] |
| [def :-) [$images/smiley.png]] |
| [def __jam__ [$images/jam.png]] |
| |
| [section 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 <boost/python.hpp> |
| |
| BOOST_PYTHON_MODULE(hello_ext) |
| { |
| using namespace boost::python; |
| 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: |
| |
| [python] |
| |
| >>> import hello_ext |
| >>> print hello.greet() |
| hello, world |
| |
| [c++] |
| |
| [:['[*Next stop... Building your Hello World module from start to finish...]]] |
| |
| [endsect] |
| [section:hello 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 will outline the steps |
| necessary to achieve that. We will use the build tool that comes bundled |
| with every boost distribution: [*bjam]. |
| |
| [note [*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 will 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 |
| the DLLs and run a python program using the extension. |
| |
| The tutorial example can be found in the directory: |
| [^libs/python/example/tutorial]. There, you can find: |
| |
| * hello.cpp |
| * hello.py |
| * Jamroot |
| |
| The [^hello.cpp] file is our C++ hello world example. The [^Jamroot] is |
| a minimalist ['bjam] script that builds the DLLs for us. Finally, |
| [^hello.py] is our Python program that uses the extension in |
| [^hello.cpp]. |
| |
| Before anything else, you should have the bjam executable in your boost |
| directory or somewhere in your path such that [^bjam] can be executed in |
| the command line. Pre-built Boost.Jam executables are available for most |
| platforms. The complete list of Bjam executables can be found |
| [@http://sourceforge.net/project/showfiles.php?group_id=7586 here]. |
| |
| [h2 Let's Jam!] |
| __jam__ |
| |
| [@../../../../example/tutorial/Jamroot Here] is our minimalist Jamroot |
| file. Simply copy the file and tweak [^use-project boost] to where your |
| boost root directory is and your OK. |
| |
| The comments contained in the Jamrules file above should be sufficient |
| to get you going. |
| |
| [h2 Running bjam] |
| |
| ['bjam] is run using your operating system's command line interpreter. |
| |
| [:Start it up.] |
| |
| A file called user-config.jam in your home directory is used to |
| configure your tools. In Windows, your home directory can be found by |
| typing: |
| |
| [pre |
| ECHO %HOMEDRIVE%%HOMEPATH% |
| ] |
| |
| into a command prompt window. Your file should at least have the rules |
| for your compiler and your python installation. A specific example of |
| this on Windows would be: |
| |
| [pre |
| # MSVC configuration |
| using msvc : 8.0 ; |
| |
| # Python configuration |
| using python : 2.4 : C:/dev/tools/Python/ ; |
| ] |
| |
| The first rule tells Bjam to use the MSVC 8.0 compiler and associated |
| tools. The second rule provides information on Python, its version and |
| where it is located. The above assumes that the Python installation is |
| in [^C:/dev/tools\/Python/]. If you have one fairly "standard" python |
| installation for your platform, you might not need to do this. |
| |
| Now we are ready... Be sure to [^cd] to [^libs/python/example/tutorial] |
| where the tutorial [^"hello.cpp"] and the [^"Jamroot"] is situated. |
| |
| Finally: |
| |
| bjam |
| |
| It should be building now: |
| |
| [pre |
| cd C:\dev\boost\libs\python\example\tutorial |
| bjam |
| ...patience... |
| ...found 1101 targets... |
| ...updating 35 targets... |
| ] |
| |
| And so on... Finally: |
| |
| [pre |
| Creating library /path-to-boost_python.dll/ |
| Creating library /path-to-'''hello_ext'''.exp/ |
| '''**passed**''' ... hello.test |
| ...updated 35 targets... |
| ] |
| |
| Or something similar. If all is well, you should now have built the DLLs and |
| run the Python program. |
| |
| [:[*There you go... Have fun!]] |
| |
| [endsect] |
| [section:exposing 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: |
| |
| [python] |
| |
| >>> import hello |
| >>> planet = hello.World() |
| >>> planet.set('howdy') |
| >>> planet.greet() |
| 'howdy' |
| |
| [section 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: |
| |
| [c++] |
| |
| 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. |
| |
| [endsect] |
| [section 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: |
| |
| [python] |
| |
| >>> 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 |
| |
| [endsect] |
| [section 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: |
| |
| [c++] |
| |
| 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: |
| |
| [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: |
| |
| [c++] |
| |
| .add_property("rovalue", &Num::get) |
| |
| [endsect] |
| [section 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: |
| |
| # 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 will 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 will see more of |
| Boost.Python [link python.call_policies call policies] later. |
| |
| // Tell Python to take ownership of factory's result |
| def("factory", factory, |
| return_value_policy<manage_new_object>()); |
| |
| [endsect] |
| |
| [section Class Virtual Functions] |
| |
| In this section, we will learn how to make functions behave polymorphically |
| through virtual functions. Continuing our example, let us add a virtual function |
| to our [^Base] class: |
| |
| struct Base |
| { |
| virtual ~Base() {} |
| virtual int f() = 0; |
| }; |
| |
| One of the goals of Boost.Python is to be minimally intrusive on an existing C++ |
| design. In principle, it should be possible to expose the interface for a 3rd |
| party library without changing it. It is not ideal to add anything to our class |
| `Base`. Yet, when you have a virtual function that's going to be overridden in |
| Python and called polymorphically *from C++*, we'll need to add some |
| scaffoldings to make things work properly. What we'll do is write a class |
| wrapper that derives from `Base` that will unintrusively hook into the virtual |
| functions so that a Python override may be called: |
| |
| struct BaseWrap : Base, wrapper<Base> |
| { |
| int f() |
| { |
| return this->get_override("f")(); |
| } |
| }; |
| |
| Notice too that in addition to inheriting from `Base`, we also multiply- |
| inherited `wrapper<Base>` (See [@../../../v2/wrapper.html Wrapper]). The |
| `wrapper` template makes the job of wrapping classes that are meant to |
| overridden in Python, easier. |
| |
| [blurb __alert__ [*MSVC6/7 Workaround] |
| |
| If you are using Microsoft Visual C++ 6 or 7, you have to write `f` as: |
| |
| `return call<int>(this->get_override("f").ptr());`.] |
| |
| BaseWrap's overridden virtual member function `f` in effect calls the |
| corresponding method of the Python object through `get_override`. |
| |
| Finally, exposing `Base`: |
| |
| class_<BaseWrap, boost::noncopyable>("Base") |
| .def("f", pure_virtual(&Base::f)) |
| ; |
| |
| `pure_virtual` signals Boost.Python that the function `f` is a pure virtual |
| function. |
| |
| [note [*member function and methods] |
| |
| Python, like many object oriented languages uses the term [*methods]. |
| Methods correspond roughly to C++'s [*member functions]] |
| |
| [endsect] |
| |
| [section Virtual Functions with Default Implementations] |
| |
| We've seen in the previous section how classes with pure virtual functions are |
| wrapped using Boost.Python's [@../../../v2/wrapper.html class wrapper] |
| facilities. If we wish to wrap [*non]-pure-virtual functions instead, the |
| mechanism is a bit different. |
| |
| Recall that in the [link python.class_virtual_functions previous section], we |
| wrapped a class with a pure virtual function that we then implemented in C++, or |
| Python classes derived from it. Our base class: |
| |
| struct Base |
| { |
| 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 ~Base() {} |
| virtual int f() { return 0; } |
| }; |
| |
| We wrap it this way: |
| |
| struct BaseWrap : Base, wrapper<Base> |
| { |
| int f() |
| { |
| if (override f = this->get_override("f")) |
| return f(); // *note* |
| return Base::f(); |
| } |
| |
| int default_f() { return this->Base::f(); } |
| }; |
| |
| Notice how we implemented `BaseWrap::f`. Now, we have to check if there is an |
| override for `f`. If none, then we call `Base::f()`. |
| |
| [blurb __alert__ [*MSVC6/7 Workaround] |
| |
| If you are using Microsoft Visual C++ 6 or 7, you have to rewrite the line |
| with the `*note*` as: |
| |
| `return call<char const*>(f.ptr());`.] |
| |
| Finally, exposing: |
| |
| class_<BaseWrap, boost::noncopyable>("Base") |
| .def("f", &Base::f, &BaseWrap::default_f) |
| ; |
| |
| Take note that we expose both `&Base::f` and `&BaseWrap::default_f`. |
| Boost.Python needs to keep track of 1) the dispatch function [^f] and 2) the |
| forwarding function to its default implementation [^default_f]. There's a |
| special [^def] function for this purpose. |
| |
| In Python, the results would be as expected: |
| |
| [python] |
| |
| >>> base = Base() |
| >>> class Derived(Base): |
| ... def f(self): |
| ... return 42 |
| ... |
| >>> derived = Derived() |
| |
| Calling [^base.f()]: |
| |
| >>> base.f() |
| 0 |
| |
| Calling [^derived.f()]: |
| |
| >>> derived.f() |
| 42 |
| |
| [endsect] |
| [section 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: |
| |
| [c++] |
| |
| 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". |
| |
| [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 |
| { public: operator double() const; }; |
| |
| Rational pow(Rational, Rational); |
| Rational abs(Rational); |
| ostream& operator<<(ostream&,Rational); |
| |
| class_<Rational>("Rational") |
| .def(float_(self)) // __float__ |
| .def(pow(self, other<Rational>)) // __pow__ |
| .def(abs(self)) // __abs__ |
| .def(str(self)) // __str__ |
| ; |
| |
| Need we say more? |
| |
| [note What is the business of `operator<<`? |
| Well, the method `str` requires the `operator<<` to do its work (i.e. |
| `operator<<` is used by the method defined by `def(str(self))`.] |
| |
| [endsect] |
| [endsect] [/ Exposing Classes ] |
| |
| [section Functions] |
| |
| In this chapter, we'll look at Boost.Python powered functions in closer |
| detail. We will see some facilities to make exposing C++ functions to |
| Python safe from potential pifalls such as dangling pointers and |
| references. We will 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! |
| ] |
| |
| [section 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: |
| |
| [python] |
| |
| >>> 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: |
| |
| [c++] |
| |
| 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<args..., |
| policy2<args..., |
| policy3<args...> > > |
| |
| 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]: Ties lifetimes of the arguments |
| * [*with_custodian_and_ward_postcall]: Ties lifetimes of the arguments and results |
| * [*return_internal_reference]: Ties lifetime of one argument to that of result |
| * [*return_value_policy<T> with T one of:] |
| * [*reference_existing_object]: naive (dangerous) approach |
| * [*copy_const_reference]: Boost.Python v1 approach |
| * [*copy_non_const_reference]: |
| * [*manage_new_object]: Adopt a pointer and hold the instance |
| |
| [blurb :-) [*Remember the Zen, Luke:] |
| |
| "Explicit is better than implicit" |
| |
| "In the face of ambiguity, refuse the temptation to guess" |
| ] |
| |
| [endsect] |
| [section 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 will 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) |
| |
| [endsect] |
| [section 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 [link python.overloading 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<int, optional<char, std::string, double> >()) |
| |
| Notice the use of [^init<...>] and [^optional<...>] to signify the default |
| (optional arguments). |
| |
| [endsect] |
| [section 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", (void(*)(bool, int, char))0, 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 |
| [link python.overloading 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 [link python.overloading 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) |
| |
| [endsect] |
| [endsect] [/ Functions ] |
| |
| [section:object 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 will 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. |
| |
| [$images/python.png] |
| |
| [section 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: |
| |
| [python] |
| |
| 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: |
| |
| [c++] |
| |
| 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. |
| |
| [endsect] |
| [section 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++. |
| |
| [blurb |
| __alert__ [*Beware] the common pitfall of forgetting that the constructors |
| of most of Python's mutable types make copies, just as in Python. |
| ] |
| |
| Python: |
| [python] |
| |
| >>> d = dict(x.__dict__) # copies x.__dict__ |
| >>> d['whatever'] = 3 # modifies the copy |
| |
| C++: |
| [c++] |
| |
| dict d(x.attr("__dict__")); // copies x.__dict__ |
| d['whatever'] = 3; // modifies the copy |
| |
| [h2 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); |
| |
| [endsect] |
| [section 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 [^double]s. 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]. The second line attempts to ['extract] the [^Vec2] object from held |
| by the Boost.Python [^object]. |
| |
| Take note that we said "attempt to" above. What if the Boost.Python [^object] |
| 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<Vec2&> x(o); |
| if (x.check()) { |
| Vec2& v = x(); ... |
| |
| __tip__ 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__ ! |
| |
| |
| [endsect] |
| [section 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. |
| |
| [note [*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 |
| [@../../../v2/scope.html here].] |
| |
| You can access those values in Python as |
| |
| [python] |
| |
| >>> 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: |
| |
| [c++] |
| |
| scope in_X = class_<X>("X") |
| .def( ... ) |
| .def( ... ) |
| ; |
| |
| // Expose X::nested as X.nested |
| enum_<X::nested>("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 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]] |
| |
| [endsect] |
| [endsect] [/ Object Interface] |
| |
| [section 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 embed python into your programs, you have to link to |
| both Boost.Python's as well as Python's own runtime library. |
| |
| Boost.Python's 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 library can be found in the [^/libs] subdirectory of |
| your Python directory. On Windows it is called pythonXY.lib where X.Y is |
| your major Python version number. |
| |
| Additionally, Python's [^/include] subdirectory has to be added to your |
| include path. |
| |
| In a Jamfile, all the above boils down to: |
| |
| [pre |
| projectroot c:\projects\embedded_program ; # location of the program |
| |
| # bring in the rules for python |
| SEARCH on python.jam = $(BOOST_BUILD_PATH) ; |
| include python.jam ; |
| |
| exe embedded_program # name of the executable |
| : #sources |
| embedded_program.cpp |
| : # requirements |
| <find-library>boost_python <library-path>c:\boost\libs\python |
| $(PYTHON_PROPERTIES) |
| <library-path>$(PYTHON_LIB_PATH) |
| <find-library>$(PYTHON_EMBEDDED_LIBRARY) ; |
| ] |
| |
| [h2 Getting started] |
| |
| 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''' [^<boost/python.hpp>] |
| |
| # Call Py_Initialize() to start the interpreter and create the [^__main__] module. |
| |
| # Call other Python C API routines to use the interpreter. |
| |
| [/ # Call Py_Finalize() to stop the interpreter and release its resources.] |
| |
| [note [*Note that at this time you must not call Py_Finalize() to stop the |
| interpreter. This may be fixed in a future version of boost.python.] |
| ] |
| |
| (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...]]] |
| |
| [section 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/c-api/refcounting.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 Running Python code] |
| |
| Boost.python provides three related functions to run Python code from C++. |
| |
| object eval(str expression, object globals = object(), object locals = object()) |
| object exec(str code, object globals = object(), object locals = object()) |
| object exec_file(str filename, object globals = object(), object locals = object()) |
| |
| eval evaluates the given expression and returns the resulting value. |
| exec executes the given code (typically a set of statements) returning the result, |
| and exec_file executes the code contained in the given file. |
| |
| 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. |
| |
| Boost.python provides a function to import a module: |
| |
| object import(str name) |
| |
| import imports a python module (potentially loading it into the running process |
| first), and returns it. |
| |
| Let's import the [^__main__] module and run some Python code in its namespace: |
| |
| object main_module = import("__main__"); |
| object main_namespace = main_module.attr("__dict__"); |
| |
| object ignored = exec("hello = file('hello.txt', 'w')\n" |
| "hello.write('Hello world!')\n" |
| "hello.close()", |
| main_namespace); |
| |
| This should create a file called 'hello.txt' in the current directory |
| containing a phrase that is well-known in programming circles. |
| |
| [h2 Manipulating Python objects] |
| |
| Often we'd like to have a class to manipulate Python objects. |
| But we have already seen such a class above, and in the |
| [@python/object.html previous section]: the aptly named [^object] class |
| and its derivatives. We've already seen that they can be constructed from |
| a [^handle]. The following examples should further illustrate this fact: |
| |
| object main_module = import("__main__"); |
| object main_namespace = main_module.attr("__dict__"); |
| object ignored = exec("result = 5 ** 2", main_namespace); |
| 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 use eval instead, |
| which returns the result directly: |
| |
| object result = eval("5 ** 2"); |
| int five_squared = extract<int>(result); |
| |
| [h2 Exception handling] |
| |
| If an exception occurs in the evaluation of the python expression, |
| [@../../../v2/errors.html#error_already_set-spec error_already_set] is thrown: |
| |
| try |
| { |
| object result = eval("5/0"); |
| // execution will never get here: |
| int five_divided_by_zero = extract<int>(result); |
| } |
| catch(error_already_set const &) |
| { |
| // 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 const &) |
| { |
| 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].) |
| |
| [endsect] |
| [endsect] [/ Embedding] |
| |
| [section 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: |
| |
| [python] |
| |
| 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: |
| |
| [c++] |
| |
| 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: |
| |
| * range(start, finish) |
| * range<Policies,Target>(start, finish) |
| |
| Here, start/finish may be one of: |
| |
| * member data pointers |
| * member function pointers |
| * adaptable function object (use Target parameter) |
| |
| [*iterator] |
| |
| * iterator<T, Policies>() |
| |
| 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: |
| |
| [python] |
| |
| f = Field() |
| for x in f.pions: |
| smash(x) |
| for y in f.bogons: |
| count(y) |
| |
| Now, our C++ Wrapper: |
| |
| [c++] |
| |
| class_<F>("Field") |
| .property("pions", range(&F::p_begin, &F::p_end)) |
| .property("bogons", range(&F::b_begin, &F::b_end)); |
| |
| [*stl_input_iterator] |
| |
| So far, we have seen how to expose C++ iterators and ranges to Python. |
| Sometimes we wish to go the other way, though: we'd like to pass a |
| Python sequence to an STL algorithm or use it to initialize an STL |
| container. We need to make a Python iterator look like an STL iterator. |
| For that, we use `stl_input_iterator<>`. Consider how we might |
| implement a function that exposes `std::list<int>::assign()` to |
| Python: |
| |
| [c++] |
| |
| template<typename T> |
| void list_assign(std::list<T>& l, object o) { |
| // Turn a Python sequence into an STL input range |
| stl_input_iterator<T> begin(o), end; |
| l.assign(begin, end); |
| } |
| |
| // Part of the wrapper for list<int> |
| class_<std::list<int> >("list_int") |
| .def("assign", &list_assign<int>) |
| // ... |
| ; |
| |
| Now in Python, we can assign any integer sequence to `list_int` objects: |
| |
| [python] |
| |
| x = list_int(); |
| x.assign([1,2,3,4,5]) |
| |
| [endsect] |
| [section:exception 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); |
| ... |
| |
| [endsect] |
| [section:techniques General Techniques] |
| |
| Here are presented some useful techniques that you can use while wrapping code with Boost.Python. |
| |
| [section 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]. |
| |
| [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: |
| |
| [python] |
| |
| >>> 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: |
| |
| [c++] |
| |
| /* 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: |
| |
| [python] |
| |
| >>> 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(...) |
| |
| [endsect] |
| [section 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++: |
| |
| [c++] |
| |
| class point {...}; |
| |
| BOOST_PYTHON_MODULE(_geom) |
| { |
| class_<point>("point")...; |
| } |
| |
| If we are using the technique from the previous session, |
| [link python.creating_packages Creating Packages], we can code directly |
| into [^geom/\_\_init\_\_.py]: |
| |
| [python] |
| |
| 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. |
| |
| [endsect] |
| [section 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: |
| |
| [c++] |
| |
| /* 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. |
| |
| [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.] |
| |
| [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].] |
| |
| [endsect] |
| [endsect] [/ General Techniques] |
| |
| |