2
0
mirror of https://github.com/boostorg/python.git synced 2026-01-19 04:22:16 +00:00

This commit was manufactured by cvs2svn to create tag

'merged_to_RC_1_32_0'.

[SVN r26255]
This commit is contained in:
nobody
2004-11-19 14:17:03 +00:00
parent 92ff4ab76f
commit 275e5ee6ad
44 changed files with 6103 additions and 6431 deletions

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -1,947 +1 @@
+++++++++++++++++++++++++++++++++++++++++++
Building Hybrid Systems with Boost.Python
+++++++++++++++++++++++++++++++++++++++++++
:Author: David Abrahams
:Contact: dave@boost-consulting.com
:organization: `Boost Consulting`_
:date: $Date$
:Author: Ralf W. Grosse-Kunstleve
:copyright: Copyright David Abrahams and Ralf W. Grosse-Kunstleve 2003. All rights reserved
.. contents:: Table of Contents
.. _`Boost Consulting`: http://www.boost-consulting.com
==========
Abstract
==========
Boost.Python is an open source C++ library which provides a concise
IDL-like interface for binding C++ classes and functions to
Python. Leveraging the full power of C++ compile-time introspection
and of recently developed metaprogramming techniques, this is achieved
entirely in pure C++, without introducing a new syntax.
Boost.Python's rich set of features and high-level interface make it
possible to engineer packages from the ground up as hybrid systems,
giving programmers easy and coherent access to both the efficient
compile-time polymorphism of C++ and the extremely convenient run-time
polymorphism of Python.
==============
Introduction
==============
Python and C++ are in many ways as different as two languages could
be: while C++ is usually compiled to machine-code, Python is
interpreted. Python's dynamic type system is often cited as the
foundation of its flexibility, while in C++ static typing is the
cornerstone of its efficiency. C++ has an intricate and difficult
compile-time meta-language, while in Python, practically everything
happens at runtime.
Yet for many programmers, these very differences mean that Python and
C++ complement one another perfectly. Performance bottlenecks in
Python programs can be rewritten in C++ for maximal speed, and
authors of powerful C++ libraries choose Python as a middleware
language for its flexible system integration capabilities.
Furthermore, the surface differences mask some strong similarities:
* 'C'-family control structures (if, while, for...)
* Support for object-orientation, functional programming, and generic
programming (these are both *multi-paradigm* programming languages.)
* Comprehensive operator overloading facilities, recognizing the
importance of syntactic variability for readability and
expressivity.
* High-level concepts such as collections and iterators.
* High-level encapsulation facilities (C++: namespaces, Python: modules)
to support the design of re-usable libraries.
* Exception-handling for effective management of error conditions.
* C++ idioms in common use, such as handle/body classes and
reference-counted smart pointers mirror Python reference semantics.
Given Python's rich 'C' interoperability API, it should in principle
be possible to expose C++ type and function interfaces to Python with
an analogous interface to their C++ counterparts. However, the
facilities provided by Python alone for integration with C++ are
relatively meager. Compared to C++ and Python, 'C' has only very
rudimentary abstraction facilities, and support for exception-handling
is completely missing. 'C' extension module writers are required to
manually manage Python reference counts, which is both annoyingly
tedious and extremely error-prone. Traditional extension modules also
tend to contain a great deal of boilerplate code repetition which
makes them difficult to maintain, especially when wrapping an evolving
API.
These limitations have lead to the development of a variety of wrapping
systems. SWIG_ is probably the most popular package for the
integration of C/C++ and Python. A more recent development is SIP_,
which was specifically designed for interfacing Python with the Qt_
graphical user interface library. Both SWIG and SIP introduce their
own specialized languages for customizing inter-language bindings.
This has certain advantages, but having to deal with three different
languages (Python, C/C++ and the interface language) also introduces
practical and mental difficulties. The CXX_ package demonstrates an
interesting alternative. It shows that at least some parts of
Python's 'C' API can be wrapped and presented through a much more
user-friendly C++ interface. However, unlike SWIG and SIP, CXX does
not include support for wrapping C++ classes as new Python types.
The features and goals of Boost.Python_ overlap significantly with
many of these other systems. That said, Boost.Python attempts to
maximize convenience and flexibility without introducing a separate
wrapping language. Instead, it presents the user with a high-level
C++ interface for wrapping C++ classes and functions, managing much of
the complexity behind-the-scenes with static metaprogramming.
Boost.Python also goes beyond the scope of earlier systems by
providing:
* Support for C++ virtual functions that can be overridden in Python.
* Comprehensive lifetime management facilities for low-level C++
pointers and references.
* Support for organizing extensions as Python packages,
with a central registry for inter-language type conversions.
* A safe and convenient mechanism for tying into Python's powerful
serialization engine (pickle).
* Coherence with the rules for handling C++ lvalues and rvalues that
can only come from a deep understanding of both the Python and C++
type systems.
The key insight that sparked the development of Boost.Python is that
much of the boilerplate code in traditional extension modules could be
eliminated using C++ compile-time introspection. Each argument of a
wrapped C++ function must be extracted from a Python object using a
procedure that depends on the argument type. Similarly the function's
return type determines how the return value will be converted from C++
to Python. Of course argument and return types are part of each
function's type, and this is exactly the source from which
Boost.Python deduces most of the information required.
This approach leads to *user guided wrapping*: as much information is
extracted directly from the source code to be wrapped as is possible
within the framework of pure C++, and some additional information is
supplied explicitly by the user. Mostly the guidance is mechanical
and little real intervention is required. Because the interface
specification is written in the same full-featured language as the
code being exposed, the user has unprecedented power available when
she does need to take control.
.. _Python: http://www.python.org/
.. _SWIG: http://www.swig.org/
.. _SIP: http://www.riverbankcomputing.co.uk/sip/index.php
.. _Qt: http://www.trolltech.com/
.. _CXX: http://cxx.sourceforge.net/
.. _Boost.Python: http://www.boost.org/libs/python/doc
===========================
Boost.Python Design Goals
===========================
The primary goal of Boost.Python is to allow users to expose C++
classes and functions to Python using nothing more than a C++
compiler. In broad strokes, the user experience should be one of
directly manipulating C++ objects from Python.
However, it's also important not to translate all interfaces *too*
literally: the idioms of each language must be respected. For
example, though C++ and Python both have an iterator concept, they are
expressed very differently. Boost.Python has to be able to bridge the
interface gap.
It must be possible to insulate Python users from crashes resulting
from trivial misuses of C++ interfaces, such as accessing
already-deleted objects. By the same token the library should
insulate C++ users from low-level Python 'C' API, replacing
error-prone 'C' interfaces like manual reference-count management and
raw ``PyObject`` pointers with more-robust alternatives.
Support for component-based development is crucial, so that C++ types
exposed in one extension module can be passed to functions exposed in
another without loss of crucial information like C++ inheritance
relationships.
Finally, all wrapping must be *non-intrusive*, without modifying or
even seeing the original C++ source code. Existing C++ libraries have
to be wrappable by third parties who only have access to header files
and binaries.
==========================
Hello Boost.Python World
==========================
And now for a preview of Boost.Python, and how it improves on the raw
facilities offered by Python. Here's a function we might want to
expose::
char const* greet(unsigned x)
{
static char const* const msgs[] = { "hello", "Boost.Python", "world!" };
if (x > 2)
throw std::range_error("greet: index out of range");
return msgs[x];
}
To wrap this function in standard C++ using the Python 'C' API, we'd
need something like this::
extern "C" // all Python interactions use 'C' linkage and calling convention
{
// Wrapper to handle argument/result conversion and checking
PyObject* greet_wrap(PyObject* args, PyObject * keywords)
{
int x;
if (PyArg_ParseTuple(args, "i", &x)) // extract/check arguments
{
char const* result = greet(x); // invoke wrapped function
return PyString_FromString(result); // convert result to Python
}
return 0; // error occurred
}
// Table of wrapped functions to be exposed by the module
static PyMethodDef methods[] = {
{ "greet", greet_wrap, METH_VARARGS, "return one of 3 parts of a greeting" }
, { NULL, NULL, 0, NULL } // sentinel
};
// module initialization function
DL_EXPORT init_hello()
{
(void) Py_InitModule("hello", methods); // add the methods to the module
}
}
Now here's the wrapping code we'd use to expose it with Boost.Python::
#include <boost/python.hpp>
using namespace boost::python;
BOOST_PYTHON_MODULE(hello)
{
def("greet", greet, "return one of 3 parts of a greeting");
}
and here it is in action::
>>> import hello
>>> for x in range(3):
... print hello.greet(x)
...
hello
Boost.Python
world!
Aside from the fact that the 'C' API version is much more verbose,
it's worth noting a few things that it doesn't handle correctly:
* The original function accepts an unsigned integer, and the Python
'C' API only gives us a way of extracting signed integers. The
Boost.Python version will raise a Python exception if we try to pass
a negative number to ``hello.greet``, but the other one will proceed
to do whatever the C++ implementation does when converting an
negative integer to unsigned (usually wrapping to some very large
number), and pass the incorrect translation on to the wrapped
function.
* That brings us to the second problem: if the C++ ``greet()``
function is called with a number greater than 2, it will throw an
exception. Typically, if a C++ exception propagates across the
boundary with code generated by a 'C' compiler, it will cause a
crash. As you can see in the first version, there's no C++
scaffolding there to prevent this from happening. Functions wrapped
by Boost.Python automatically include an exception-handling layer
which protects Python users by translating unhandled C++ exceptions
into a corresponding Python exception.
* A slightly more-subtle limitation is that the argument conversion
used in the Python 'C' API case can only get that integer ``x`` in
*one way*. PyArg_ParseTuple can't convert Python ``long`` objects
(arbitrary-precision integers) which happen to fit in an ``unsigned
int`` but not in a ``signed long``, nor will it ever handle a
wrapped C++ class with a user-defined implicit ``operator unsigned
int()`` conversion. Boost.Python's dynamic type conversion
registry allows users to add arbitrary conversion methods.
==================
Library Overview
==================
This section outlines some of the library's major features. Except as
neccessary to avoid confusion, details of library implementation are
omitted.
------------------
Exposing Classes
------------------
C++ classes and structs are exposed with a similarly-terse interface.
Given::
struct World
{
void set(std::string msg) { this->msg = msg; }
std::string greet() { return msg; }
std::string msg;
};
The following code will expose it in our extension module::
#include <boost/python.hpp>
BOOST_PYTHON_MODULE(hello)
{
class_<World>("World")
.def("greet", &World::greet)
.def("set", &World::set)
;
}
Although this code has a certain pythonic familiarity, people
sometimes find the syntax bit confusing because it doesn't look like
most of the C++ code they're used to. All the same, this is just
standard C++. Because of their flexible syntax and operator
overloading, C++ and Python are great for defining domain-specific
(sub)languages
(DSLs), and that's what we've done in Boost.Python. To break it down::
class_<World>("World")
constructs an unnamed object of type ``class_<World>`` and passes
``"World"`` to its constructor. This creates a new-style Python class
called ``World`` in the extension module, and associates it with the
C++ type ``World`` in the Boost.Python type conversion registry. We
might have also written::
class_<World> w("World");
but that would've been more verbose, since we'd have to name ``w``
again to invoke its ``def()`` member function::
w.def("greet", &World::greet)
There's nothing special about the location of the dot for member
access in the original example: C++ allows any amount of whitespace on
either side of a token, and placing the dot at the beginning of each
line allows us to chain as many successive calls to member functions
as we like with a uniform syntax. The other key fact that allows
chaining is that ``class_<>`` member functions all return a reference
to ``*this``.
So the example is equivalent to::
class_<World> w("World");
w.def("greet", &World::greet);
w.def("set", &World::set);
It's occasionally useful to be able to break down the components of a
Boost.Python class wrapper in this way, but the rest of this article
will stick to the terse syntax.
For completeness, here's the wrapped class in use: ::
>>> import hello
>>> planet = hello.World()
>>> planet.set('howdy')
>>> planet.greet()
'howdy'
Constructors
============
Since our ``World`` class is just a plain ``struct``, it has an
implicit no-argument (nullary) constructor. Boost.Python exposes the
nullary constructor by default, which is why we were able to write: ::
>>> planet = hello.World()
However, well-designed classes in any language may require constructor
arguments in order to establish their invariants. Unlike Python,
where ``__init__`` is just a specially-named method, In C++
constructors cannot be handled like ordinary member functions. In
particular, we can't take their address: ``&World::World`` is an
error. The library provides a different interface for specifying
constructors. Given::
struct World
{
World(std::string msg); // added constructor
...
we can modify our wrapping code as follows::
class_<World>("World", init<std::string>())
...
of course, a C++ class may have additional constructors, and we can
expose those as well by passing more instances of ``init<...>`` to
``def()``::
class_<World>("World", init<std::string>())
.def(init<double, double>())
...
Boost.Python allows wrapped functions, member functions, and
constructors to be overloaded to mirror C++ overloading.
Data Members and Properties
===========================
Any publicly-accessible data members in a C++ class can be easily
exposed as either ``readonly`` or ``readwrite`` attributes::
class_<World>("World", init<std::string>())
.def_readonly("msg", &World::msg)
...
and can be used directly in Python: ::
>>> planet = hello.World('howdy')
>>> planet.msg
'howdy'
This does *not* result in adding attributes to the ``World`` instance
``__dict__``, which can result in substantial memory savings when
wrapping large data structures. In fact, no instance ``__dict__``
will be created at all unless attributes are explicitly added from
Python. Boost.Python owes this capability to the new Python 2.2 type
system, in particular the descriptor interface and ``property`` type.
In C++, publicly-accessible data members are considered a sign of poor
design because they break encapsulation, and style guides usually
dictate the use of "getter" and "setter" functions instead. In
Python, however, ``__getattr__``, ``__setattr__``, and since 2.2,
``property`` mean that attribute access is just one more
well-encapsulated syntactic tool at the programmer's disposal.
Boost.Python bridges this idiomatic gap by making Python ``property``
creation directly available to users. If ``msg`` were private, we
could still expose it as attribute in Python as follows::
class_<World>("World", init<std::string>())
.add_property("msg", &World::greet, &World::set)
...
The example above mirrors the familiar usage of properties in Python
2.2+: ::
>>> class World(object):
... __init__(self, msg):
... self.__msg = msg
... def greet(self):
... return self.__msg
... def set(self, msg):
... self.__msg = msg
... msg = property(greet, set)
Operator Overloading
====================
The ability to write arithmetic operators for user-defined types has
been a major factor in the success of both languages for numerical
computation, and the success of packages like NumPy_ attests to the
power of exposing operators in extension modules. Boost.Python
provides a concise mechanism for wrapping operator overloads. The
example below shows a fragment from a wrapper for the Boost rational
number library::
class_<rational<int> >("rational_int")
.def(init<int, int>()) // constructor, e.g. rational_int(3,4)
.def("numerator", &rational<int>::numerator)
.def("denominator", &rational<int>::denominator)
.def(-self) // __neg__ (unary minus)
.def(self + self) // __add__ (homogeneous)
.def(self * self) // __mul__
.def(self + int()) // __add__ (heterogenous)
.def(int() + self) // __radd__
...
The magic is performed using a simplified application of "expression
templates" [VELD1995]_, a technique originally developed for
optimization of high-performance matrix algebra expressions. The
essence is that instead of performing the computation immediately,
operators are overloaded to construct a type *representing* the
computation. In matrix algebra, dramatic optimizations are often
available when the structure of an entire expression can be taken into
account, rather than evaluating each operation "greedily".
Boost.Python uses the same technique to build an appropriate Python
method object based on expressions involving ``self``.
.. _NumPy: http://www.pfdubois.com/numpy/
Inheritance
===========
C++ inheritance relationships can be represented to Boost.Python by adding
an optional ``bases<...>`` argument to the ``class_<...>`` template
parameter list as follows::
class_<Derived, bases<Base1,Base2> >("Derived")
...
This has two effects:
1. When the ``class_<...>`` is created, Python type objects
corresponding to ``Base1`` and ``Base2`` are looked up in
Boost.Python's registry, and are used as bases for the new Python
``Derived`` type object, so methods exposed for the Python ``Base1``
and ``Base2`` types are automatically members of the ``Derived``
type. Because the registry is global, this works correctly even if
``Derived`` is exposed in a different module from either of its
bases.
2. C++ conversions from ``Derived`` to its bases are added to the
Boost.Python registry. Thus wrapped C++ methods expecting (a
pointer or reference to) an object of either base type can be
called with an object wrapping a ``Derived`` instance. Wrapped
member functions of class ``T`` are treated as though they have an
implicit first argument of ``T&``, so these conversions are
neccessary to allow the base class methods to be called for derived
objects.
Of course it's possible to derive new Python classes from wrapped C++
class instances. Because Boost.Python uses the new-style class
system, that works very much as for the Python built-in types. There
is one significant detail in which it differs: the built-in types
generally establish their invariants in their ``__new__`` function, so
that derived classes do not need to call ``__init__`` on the base
class before invoking its methods : ::
>>> class L(list):
... def __init__(self):
... pass
...
>>> L().reverse()
>>>
Because C++ object construction is a one-step operation, C++ instance
data cannot be constructed until the arguments are available, in the
``__init__`` function: ::
>>> class D(SomeBoostPythonClass):
... def __init__(self):
... pass
...
>>> D().some_boost_python_method()
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: bad argument type for built-in operation
This happened because Boost.Python couldn't find instance data of type
``SomeBoostPythonClass`` within the ``D`` instance; ``D``'s ``__init__``
function masked construction of the base class. It could be corrected
by either removing ``D``'s ``__init__`` function or having it call
``SomeBoostPythonClass.__init__(...)`` explicitly.
Virtual Functions
=================
Deriving new types in Python from extension classes is not very
interesting unless they can be used polymorphically from C++. In
other words, Python method implementations should appear to override
the implementation of C++ virtual functions when called *through base
class pointers/references from C++*. Since the only way to alter the
behavior of a virtual function is to override it in a derived class,
the user must build a special derived class to dispatch a polymorphic
class' virtual functions::
//
// interface to wrap:
//
class Base
{
public:
virtual int f(std::string x) { return 42; }
virtual ~Base();
};
int calls_f(Base const& b, std::string x) { return b.f(x); }
//
// Wrapping Code
//
// Dispatcher class
struct BaseWrap : Base
{
// Store a pointer to the Python object
BaseWrap(PyObject* self_) : self(self_) {}
PyObject* self;
// Default implementation, for when f is not overridden
int f_default(std::string x) { return this->Base::f(x); }
// Dispatch implementation
int f(std::string x) { return call_method<int>(self, "f", x); }
};
...
def("calls_f", calls_f);
class_<Base, BaseWrap>("Base")
.def("f", &Base::f, &BaseWrap::f_default)
;
Now here's some Python code which demonstrates: ::
>>> class Derived(Base):
... def f(self, s):
... return len(s)
...
>>> calls_f(Base(), 'foo')
42
>>> calls_f(Derived(), 'forty-two')
9
Things to notice about the dispatcher class:
* The key element which allows overriding in Python is the
``call_method`` invocation, which uses the same global type
conversion registry as the C++ function wrapping does to convert its
arguments from C++ to Python and its return type from Python to C++.
* Any constructor signatures you wish to wrap must be replicated with
an initial ``PyObject*`` argument
* The dispatcher must store this argument so that it can be used to
invoke ``call_method``
* The ``f_default`` member function is needed when the function being
exposed is not pure virtual; there's no other way ``Base::f`` can be
called on an object of type ``BaseWrap``, since it overrides ``f``.
Deeper Reflection on the Horizon?
=================================
Admittedly, this formula is tedious to repeat, especially on a project
with many polymorphic classes. That it is neccessary reflects some
limitations in C++'s compile-time introspection capabilities: there's
no way to enumerate the members of a class and find out which are
virtual functions. At least one very promising project has been
started to write a front-end which can generate these dispatchers (and
other wrapping code) automatically from C++ headers.
Pyste_ is being developed by Bruno da Silva de Oliveira. It builds on
GCC_XML_, which generates an XML version of GCC's internal program
representation. Since GCC is a highly-conformant C++ compiler, this
ensures correct handling of the most-sophisticated template code and
full access to the underlying type system. In keeping with the
Boost.Python philosophy, a Pyste interface description is neither
intrusive on the code being wrapped, nor expressed in some unfamiliar
language: instead it is a 100% pure Python script. If Pyste is
successful it will mark a move away from wrapping everything directly
in C++ for many of our users. It will also allow us the choice to
shift some of the metaprogram code from C++ to Python. We expect that
soon, not only our users but the Boost.Python developers themselves
will be "thinking hybrid" about their own code.
.. _`GCC_XML`: http://www.gccxml.org/HTML/Index.html
.. _`Pyste`: http://www.boost.org/libs/python/pyste
---------------
Serialization
---------------
*Serialization* is the process of converting objects in memory to a
form that can be stored on disk or sent over a network connection. The
serialized object (most often a plain string) can be retrieved and
converted back to the original object. A good serialization system will
automatically convert entire object hierarchies. Python's standard
``pickle`` module is just such a system. It leverages the language's strong
runtime introspection facilities for serializing practically arbitrary
user-defined objects. With a few simple and unintrusive provisions this
powerful machinery can be extended to also work for wrapped C++ objects.
Here is an example::
#include <string>
struct World
{
World(std::string a_msg) : msg(a_msg) {}
std::string greet() const { return msg; }
std::string msg;
};
#include <boost/python.hpp>
using namespace boost::python;
struct World_picklers : pickle_suite
{
static tuple
getinitargs(World const& w) { return make_tuple(w.greet()); }
};
BOOST_PYTHON_MODULE(hello)
{
class_<World>("World", init<std::string>())
.def("greet", &World::greet)
.def_pickle(World_picklers())
;
}
Now let's create a ``World`` object and put it to rest on disk::
>>> import hello
>>> import pickle
>>> a_world = hello.World("howdy")
>>> pickle.dump(a_world, open("my_world", "w"))
In a potentially *different script* on a potentially *different
computer* with a potentially *different operating system*::
>>> import pickle
>>> resurrected_world = pickle.load(open("my_world", "r"))
>>> resurrected_world.greet()
'howdy'
Of course the ``cPickle`` module can also be used for faster
processing.
Boost.Python's ``pickle_suite`` fully supports the ``pickle`` protocol
defined in the standard Python documentation. Like a __getinitargs__
function in Python, the pickle_suite's getinitargs() is responsible for
creating the argument tuple that will be use to reconstruct the pickled
object. The other elements of the Python pickling protocol,
__getstate__ and __setstate__ can be optionally provided via C++
getstate and setstate functions. C++'s static type system allows the
library to ensure at compile-time that nonsensical combinations of
functions (e.g. getstate without setstate) are not used.
Enabling serialization of more complex C++ objects requires a little
more work than is shown in the example above. Fortunately the
``object`` interface (see next section) greatly helps in keeping the
code manageable.
------------------
Object interface
------------------
Experienced 'C' language extension module authors will be familiar
with the ubiquitous ``PyObject*``, manual reference-counting, and the
need to remember which API calls return "new" (owned) references or
"borrowed" (raw) references. These constraints are not just
cumbersome but also a major source of errors, especially in the
presence of exceptions.
Boost.Python provides a class ``object`` which automates reference
counting and provides conversion to Python from C++ objects of
arbitrary type. This significantly reduces the learning effort for
prospective extension module writers.
Creating an ``object`` from any other type is extremely simple::
object s("hello, world"); // s manages a Python string
``object`` has templated interactions with all other types, with
automatic to-python conversions. It happens so naturally that it's
easily overlooked::
object ten_Os = 10 * s[4]; // -> "oooooooooo"
In the example above, ``4`` and ``10`` are converted to Python objects
before the indexing and multiplication operations are invoked.
The ``extract<T>`` class template can be used to convert Python objects
to C++ types::
double x = extract<double>(o);
If a conversion in either direction cannot be performed, an
appropriate exception is thrown at runtime.
The ``object`` type is accompanied by a set of derived types
that mirror the Python built-in types such as ``list``, ``dict``,
``tuple``, etc. as much as possible. This enables convenient
manipulation of these high-level types from C++::
dict d;
d["some"] = "thing";
d["lucky_number"] = 13;
list l = d.keys();
This almost looks and works like regular Python code, but it is pure
C++. Of course we can wrap C++ functions which accept or return
``object`` instances.
=================
Thinking hybrid
=================
Because of the practical and mental difficulties of combining
programming languages, it is common to settle a single language at the
outset of any development effort. For many applications, performance
considerations dictate the use of a compiled language for the core
algorithms. Unfortunately, due to the complexity of the static type
system, the price we pay for runtime performance is often a
significant increase in development time. Experience shows that
writing maintainable C++ code usually takes longer and requires *far*
more hard-earned working experience than developing comparable Python
code. Even when developers are comfortable working exclusively in
compiled languages, they often augment their systems by some type of
ad hoc scripting layer for the benefit of their users without ever
availing themselves of the same advantages.
Boost.Python enables us to *think hybrid*. Python can be used for
rapidly prototyping a new application; its ease of use and the large
pool of standard libraries give us a head start on the way to a
working system. If necessary, the working code can be used to
discover rate-limiting hotspots. To maximize performance these can
be reimplemented in C++, together with the Boost.Python bindings
needed to tie them back into the existing higher-level procedure.
Of course, this *top-down* approach is less attractive if it is clear
from the start that many algorithms will eventually have to be
implemented in C++. Fortunately Boost.Python also enables us to
pursue a *bottom-up* approach. We have used this approach very
successfully in the development of a toolbox for scientific
applications. The toolbox started out mainly as a library of C++
classes with Boost.Python bindings, and for a while the growth was
mainly concentrated on the C++ parts. However, as the toolbox is
becoming more complete, more and more newly added functionality can be
implemented in Python.
.. image:: python_cpp_mix.jpg
This figure shows the estimated ratio of newly added C++ and Python
code over time as new algorithms are implemented. We expect this
ratio to level out near 70% Python. Being able to solve new problems
mostly in Python rather than a more difficult statically typed
language is the return on our investment in Boost.Python. The ability
to access all of our code from Python allows a broader group of
developers to use it in the rapid development of new applications.
=====================
Development history
=====================
The first version of Boost.Python was developed in 2000 by Dave
Abrahams at Dragon Systems, where he was privileged to have Tim Peters
as a guide to "The Zen of Python". One of Dave's jobs was to develop
a Python-based natural language processing system. Since it was
eventually going to be targeting embedded hardware, it was always
assumed that the compute-intensive core would be rewritten in C++ to
optimize speed and memory footprint [#proto]_. The project also wanted to
test all of its C++ code using Python test scripts [#test]_. The only
tool we knew of for binding C++ and Python was SWIG_, and at the time
its handling of C++ was weak. It would be false to claim any deep
insight into the possible advantages of Boost.Python's approach at
this point. Dave's interest and expertise in fancy C++ template
tricks had just reached the point where he could do some real damage,
and Boost.Python emerged as it did because it filled a need and
because it seemed like a cool thing to try.
This early version was aimed at many of the same basic goals we've
described in this paper, differing most-noticeably by having a
slightly more cumbersome syntax and by lack of special support for
operator overloading, pickling, and component-based development.
These last three features were quickly added by Ullrich Koethe and
Ralf Grosse-Kunstleve [#feature]_, and other enthusiastic contributors arrived
on the scene to contribute enhancements like support for nested
modules and static member functions.
By early 2001 development had stabilized and few new features were
being added, however a disturbing new fact came to light: Ralf had
begun testing Boost.Python on pre-release versions of a compiler using
the EDG_ front-end, and the mechanism at the core of Boost.Python
responsible for handling conversions between Python and C++ types was
failing to compile. As it turned out, we had been exploiting a very
common bug in the implementation of all the C++ compilers we had
tested. We knew that as C++ compilers rapidly became more
standards-compliant, the library would begin failing on more
platforms. Unfortunately, because the mechanism was so central to the
functioning of the library, fixing the problem looked very difficult.
Fortunately, later that year Lawrence Berkeley and later Lawrence
Livermore National labs contracted with `Boost Consulting`_ for support
and development of Boost.Python, and there was a new opportunity to
address fundamental issues and ensure a future for the library. A
redesign effort began with the low level type conversion architecture,
building in standards-compliance and support for component-based
development (in contrast to version 1 where conversions had to be
explicitly imported and exported across module boundaries). A new
analysis of the relationship between the Python and C++ objects was
done, resulting in more intuitive handling for C++ lvalues and
rvalues.
The emergence of a powerful new type system in Python 2.2 made the
choice of whether to maintain compatibility with Python 1.5.2 easy:
the opportunity to throw away a great deal of elaborate code for
emulating classic Python classes alone was too good to pass up. In
addition, Python iterators and descriptors provided crucial and
elegant tools for representing similar C++ constructs. The
development of the generalized ``object`` interface allowed us to
further shield C++ programmers from the dangers and syntactic burdens
of the Python 'C' API. A great number of other features including C++
exception translation, improved support for overloaded functions, and
most significantly, CallPolicies for handling pointers and
references, were added during this period.
In October 2002, version 2 of Boost.Python was released. Development
since then has concentrated on improved support for C++ runtime
polymorphism and smart pointers. Peter Dimov's ingenious
``boost::shared_ptr`` design in particular has allowed us to give the
hybrid developer a consistent interface for moving objects back and
forth across the language barrier without loss of information. At
first, we were concerned that the sophistication and complexity of the
Boost.Python v2 implementation might discourage contributors, but the
emergence of Pyste_ and several other significant feature
contributions have laid those fears to rest. Daily questions on the
Python C++-sig and a backlog of desired improvements show that the
library is getting used. To us, the future looks bright.
.. _`EDG`: http://www.edg.com
=============
Conclusions
=============
Boost.Python achieves seamless interoperability between two rich and
complimentary language environments. Because it leverages template
metaprogramming to introspect about types and functions, the user
never has to learn a third syntax: the interface definitions are
written in concise and maintainable C++. Also, the wrapping system
doesn't have to parse C++ headers or represent the type system: the
compiler does that work for us.
Computationally intensive tasks play to the strengths of C++ and are
often impossible to implement efficiently in pure Python, while jobs
like serialization that are trivial in Python can be very difficult in
pure C++. Given the luxury of building a hybrid software system from
the ground up, we can approach design with new confidence and power.
===========
Citations
===========
.. [VELD1995] T. Veldhuizen, "Expression Templates," C++ Report,
Vol. 7 No. 5 June 1995, pp. 26-31.
http://osl.iu.edu/~tveldhui/papers/Expression-Templates/exprtmpl.html
===========
Footnotes
===========
.. [#proto] In retrospect, it seems that "thinking hybrid" from the
ground up might have been better for the NLP system: the
natural component boundaries defined by the pure python
prototype turned out to be inappropriate for getting the
desired performance and memory footprint out of the C++ core,
which eventually caused some redesign overhead on the Python
side when the core was moved to C++.
.. [#test] We also have some reservations about driving all C++
testing through a Python interface, unless that's the only way
it will be ultimately used. Any transition across language
boundaries with such different object models can inevitably
mask bugs.
.. [#feature] These features were expressed very differently in v1 of
Boost.Python
This file has been moved to http://www.boost-consulting.com/writing/bpl.txt.

View File

@@ -29,13 +29,24 @@
<hr>
<dl class="page-index">
<dt>8 Sept 2004</dt>
<dt>19 November 2004 - 1.32 release</dt>
<dd>
<ul>
<li>Updated to use the Boost Software License.</li>
<li>A new, <a href="libs/python/doc/tutorial/doc/html/python/exposing.html#python.class_virtual_functions">better method of wrapping classes with virtual functions</a> has been implemented.</li>
<li>Support for upcoming GCC symbol export control features have been folded in, thanks to Niall Douglas.</li>
<li>Improved support for <code>std::auto_ptr</code>-like types.</li>
<li>The Visual C++ bug that makes top-level <i>cv-qualification</i> of function parameter types part of the function type has been worked around.</li>
<li>Components used by other libraries have been moved out of <code>python/detail</code> and into <code> boost/detail</code> to improve dependency relationships.</li>
<li>Miscellaneous bug fixes and compiler workarounds.</li>
</ul>
</dd>
<dt>8 Sept 2004</dt>
<dd>
Support for Python's Bool type, thanks to <a
mailto="dholth-at-fastmail.fm">Daniel Holth</a>.
</ul>
</dd>
<dt>11 Sept 2003</dt>
@@ -189,12 +200,12 @@ BOOST_PYTHON_MODULE(test)
<p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
11 September 2003
19 November 2004
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p>
<p><i>&copy; Copyright <a href="../../../people/dave_abrahams.htm">Dave
Abrahams</a> 2002-2003. All Rights Reserved.</i></p>
Abrahams</a> 2002-2003.</i></p>
</body>
</html>

BIN
doc/tutorial/boost.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@@ -1,5 +1,5 @@
project boost/libs/python/doc/tutorial/doc ;
import boostbook : boostbook ;
boostbook tutorial : tutorial.qbk.xml
boostbook tutorial : tutorial.xml
;

View File

@@ -1,9 +1,9 @@
index.html
boost_python.hello.html
boost_python.exposing.html
boost_python.functions.html
boost_python.object.html
boost_python.embedding.html
boost_python.iterators.html
boost_python.exception.html
boost_python.techniques.html
python/hello.html
python/exposing.html
python/functions.html
python/object.html
python/embedding.html
python/iterators.html
python/exception.html
python/techniques.html

View File

@@ -1,238 +0,0 @@
<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>Embedding</title><link rel="stylesheet" href="boostbook.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="Chapter 1. Boost.Boost Python 1.0"><link rel="up" href="index.html" title="Chapter 1. Boost.Boost Python 1.0"><link rel="previous" href="boost_python.object.html" title=" Object Interface"><link rel="next" href="boost_python.iterators.html" title="Iterators"><link rel="chapter" href="index.html" title="Chapter 1. Boost.Boost Python 1.0"><link rel="subsection" href="boost_python.embedding.html#boost_python.using_the_interpreter" title="Using the interpreter"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><table cellpadding="2" width="100%"><td valign="top"><img src="../../../../../../boost.png" alt="boost.png (6897 bytes)" width="277" height="86"></td><td align="center"><a href="../../index.htm">Home</a></td><td align="center"><a href="libraries.html">Libraries</a></td><td align="center"><a href="../../people/people.htm">People</a></td><td align="center"><a href="../../more/faq.htm">FAQ</a></td><td align="center"><a href="../../more/index.htm">More</a></td></table><hr><div class="spirit-nav"><a accesskey="p" href="boost_python.object.html"><img src="images/prev.png" alt="Prev"></a><a accesskey="u" href="index.html"><img src="images/up.png" alt="Up"></a><a accesskey="h" href="index.html"><img src="images/home.png" alt="Home"></a><a accesskey="n" href="boost_python.iterators.html"><img src="images/next.png" alt="Next"></a></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="boost_python.embedding"></a>Embedding</h2></div></div><div></div></div><div class="toc"><dl><dt><span class="section"><a href="boost_python.embedding.html#boost_python.using_the_interpreter">Using the interpreter</a></span></dt></dl></div><p>
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 <span class="emphasis"><em>embed</em></span> the Python interpreter
into your C++ program.</p><p>
Currently, Boost.Python does not directly support everything you'll need
when embedding. Therefore you'll need to use the
<a href="http://www.python.org/doc/current/api/api.html" target="_top">
Python/C API</a> 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... <span class="inlinemediaobject"><img src="images/smiley.gif"></span></p><a name="embedding.building_embedded_programs"></a><h2><a name="id415117"></a>Building embedded programs</h2><p>
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.</p><p>
Boost.Python's static link library comes in two variants. Both are located
in Boost's <tt class="literal">/libs/python/build/bin-stage</tt> subdirectory. On Windows, the
variants are called <tt class="literal">boost_python.lib</tt> (for release builds) and
<tt class="literal">boost_python_debug.lib</tt> (for debugging). If you can't find the libraries,
you probably haven't built Boost.Python yet. See <a href="../../building.html%20Building" target="_top">
and Testing</a> on how to do this.</p><p>
Python's static link library can be found in the <tt class="literal">/libs</tt> subdirectory of
your Python directory. On Windows it is called pythonXY.lib where X.Y is
your major Python version number.</p><p>
Additionally, Python's <tt class="literal">/include</tt> subdirectory has to be added to your
include path.</p><p>
In a Jamfile, all the above boils down to:</p><pre class="programlisting"><tt class="literal"> projectroot c:\projects\embedded_program ; # location of the program</tt></pre><p>
[pre
projectroot c:\projects\embedded_program ; # location of the program</p><pre class="programlisting"><tt class="literal">
#<span class="identifier"> bring</span><span class="identifier"> in</span><span class="identifier"> the</span><span class="identifier"> rules</span><span class="keyword"> for</span><span class="identifier"> python</span><span class="identifier">
SEARCH</span><span class="identifier"> on</span><span class="identifier"> python</span><span class="special">.</span><span class="identifier">jam</span><span class="special"> =</span>#<span class="special">(</span><span class="identifier">BOOST_BUILD_PATH</span><span class="special">)</span><span class="special"> ;</span><span class="identifier">
include</span><span class="identifier"> python</span><span class="special">.</span><span class="identifier">jam</span><span class="special"> ;</span><span class="identifier">
exe</span><span class="identifier"> embedded_program</span>#<span class="identifier"> name</span><span class="identifier"> of</span><span class="identifier"> the</span><span class="identifier"> executable</span><span class="special">
:</span><span class="preprocessor"> #sources</span><span class="identifier">
embedded_program</span><span class="special">.</span><span class="identifier">cpp</span><span class="special">
:</span>#<span class="identifier"> requirements</span><span class="special">
&lt;</span><span class="identifier">find</span><span class="special">-</span><span class="identifier">library</span><span class="special">&gt;</span><span class="identifier">boost_python</span><span class="special"> &lt;</span><span class="identifier">library</span><span class="special">-</span><span class="identifier">path</span><span class="special">&gt;</span><span class="identifier">c</span><span class="special">:\</span><span class="identifier">boost</span><span class="special">\</span><span class="identifier">libs</span><span class="special">\</span><span class="identifier">python</span>#<span class="special">(</span><span class="identifier">PYTHON_PROPERTIES</span><span class="special">)</span><span class="special">
&lt;</span><span class="identifier">library</span><span class="special">-</span><span class="identifier">path</span><span class="special">&gt;</span>#<span class="special">(</span><span class="identifier">PYTHON_LIB_PATH</span><span class="special">)</span><span class="special">
&lt;</span><span class="identifier">find</span><span class="special">-</span><span class="identifier">library</span><span class="special">&gt;</span>#<span class="special">(</span><span class="identifier">PYTHON_EMBEDDED_LIBRARY</span><span class="special">)</span><span class="special"> ;</span></tt></pre><p>
# bring in the rules for python
SEARCH on python.jam = $(BOOST_BUILD_PATH) ;
include python.jam ;</p><pre class="programlisting"><tt class="literal"><span class="identifier"> exe</span><span class="identifier"> embedded_program</span>#<span class="identifier"> name</span><span class="identifier"> of</span><span class="identifier"> the</span><span class="identifier"> executable</span><span class="special">
:</span><span class="preprocessor"> #sources</span><span class="identifier">
embedded_program</span><span class="special">.</span><span class="identifier">cpp</span><span class="special">
:</span>#<span class="identifier"> requirements</span><span class="special">
&lt;</span><span class="identifier">find</span><span class="special">-</span><span class="identifier">library</span><span class="special">&gt;</span><span class="identifier">boost_python</span><span class="special"> &lt;</span><span class="identifier">library</span><span class="special">-</span><span class="identifier">path</span><span class="special">&gt;</span><span class="identifier">c</span><span class="special">:\</span><span class="identifier">boost</span><span class="special">\</span><span class="identifier">libs</span><span class="special">\</span><span class="identifier">python</span>#<span class="special">(</span><span class="identifier">PYTHON_PROPERTIES</span><span class="special">)</span><span class="special">
&lt;</span><span class="identifier">library</span><span class="special">-</span><span class="identifier">path</span><span class="special">&gt;</span>#<span class="special">(</span><span class="identifier">PYTHON_LIB_PATH</span><span class="special">)</span><span class="special">
&lt;</span><span class="identifier">find</span><span class="special">-</span><span class="identifier">library</span><span class="special">&gt;</span>#<span class="special">(</span><span class="identifier">PYTHON_EMBEDDED_LIBRARY</span><span class="special">)</span><span class="special"> ;</span></tt></pre><p>
exe embedded_program # name of the executable
: #sources
embedded_program.cpp
: # requirements
&lt;find-library&gt;boost_python &lt;library-path&gt;c:\boost\libs\python
$(PYTHON_PROPERTIES)
&lt;library-path&gt;$(PYTHON_LIB_PATH)
&lt;find-library&gt;$(PYTHON_EMBEDDED_LIBRARY) ;
]</p><a name="embedding.getting_started"></a><h2><a name="id415873"></a>Getting started</h2><p>
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:</p><div class="orderedlist"><ol type="1"><li>
#include <tt class="literal">&lt;boost/python.hpp&gt;</tt><p></p><p></p></li><li>
Call <a href="http://www.python.org/doc/current/api/initialization.html#l2h-652" target="_top">
Py_Initialize</a>() to start the interpreter and create the <tt class="literal">__main__</tt> module.<p></p><p></p></li><li>
Call other Python C API routines to use the interpreter.<p></p><p></p></li><li>
Call <a href="http://www.python.org/doc/current/api/initialization.html#l2h-656" target="_top">
Py_Finalize</a>() to stop the interpreter and release its resources.
</li></ol></div><p>
(Of course, there can be other C++ code between all of these steps.)</p><div class="blockquote"><blockquote class="blockquote"><p><span class="emphasis"><em><span class="bold"><b>Now that we can embed the interpreter in our programs, lets see how to put it to use...</b></span></em></span></p></blockquote></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="boost_python.using_the_interpreter"></a>Using the interpreter</h3></div></div><div></div></div><p>
As you probably already know, objects in Python are reference-counted.
Naturally, the <tt class="literal">PyObject</tt>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
<a href="http://www.python.org/doc/current/api/refcounts.html" target="_top">
by hand</a>. This is
messy and especially hard to get right in the presence of C++ exceptions.
Fortunately Boost.Python provides the <a href="../../v2/handle.html" target="_top">
handle</a> and
<a href="../../v2/object.html" target="_top">
object</a> class templates to automate the process.</p><a name="using_the_interpreter.reference_counting_handles_and_objects"></a><h2><a name="id416002"></a>Reference-counting handles and objects</h2><p>
There are two ways in which a function in the Python/C API can return a
<tt class="literal">PyObject*</tt>: as a <span class="emphasis"><em>borrowed reference</em></span> or as a <span class="emphasis"><em>new reference</em></span>. 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.</p><p>
For a function returning a <span class="emphasis"><em>borrowed reference</em></span> we'll have to tell the
<tt class="literal">handle</tt> that the <tt class="literal">PyObject*</tt> is borrowed with the aptly named
<a href="../../v2/handle.html#borrowed-spec" target="_top">
borrowed</a> function. Two functions
returning borrowed references are <a href="http://www.python.org/doc/current/api/importing.html#l2h-125" target="_top">
PyImport_AddModule</a> and <a href="http://www.python.org/doc/current/api/moduleObjects.html#l2h-594" target="_top">
PyModule_GetDict</a>.
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 <tt class="literal">__main__</tt> module:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> object</span><span class="identifier"> main_module</span><span class="special">((</span><span class="identifier">
handle</span><span class="special">&lt;&gt;(</span><span class="identifier">borrowed</span><span class="special">(</span><span class="identifier">PyImport_AddModule</span><span class="special">(</span><span class="string">"__main__"</span><span class="special">)))));</span><span class="identifier">
object</span><span class="identifier"> main_namespace</span><span class="special"> =</span><span class="identifier"> main_module</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"__dict__"</span><span class="special">);</span></tt></pre><p>
For a function returning a <span class="emphasis"><em>new reference</em></span> we can just create a <tt class="literal">handle</tt>
out of the raw <tt class="literal">PyObject*</tt> without wrapping it in a call to borrowed. One
such function that returns a new reference is <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55" target="_top">
PyRun_String</a> which we'll
discuss in the next section.</p><div class="informaltable"><table class="table"><colgroup><col></colgroup><tbody><tr><td><span class="inlinemediaobject"><img src="images/lens.gif"></span><span class="bold"><b>Handle is a class <span class="emphasis"><em>template</em></span>, so why haven't we been using any template parameters?</b></span><p></p><p></p><tt class="literal">handle</tt> has a single template parameter specifying the type of the managed object. This type is <tt class="literal">PyObject</tt> 99% of the time, so the parameter was defaulted to <tt class="literal">PyObject</tt> for convenience. Therefore we can use the shorthand <tt class="literal">handle&lt;&gt;</tt> instead of the longer, but equivalent, <tt class="literal">handle&lt;PyObject&gt;</tt>.
</td></tr></tbody></table></div><a name="using_the_interpreter.running_python_code"></a><h2><a name="id416300"></a>Running Python code</h2><p>
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 <a href="http://www.python.org/doc/current/api/veryhigh.html" target="_top">
here</a>. They
all work similarly so we will look at only one of them, namely:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> PyObject</span><span class="special">*</span><span class="identifier"> PyRun_String</span><span class="special">(</span><span class="keyword">char</span><span class="special"> *</span><span class="identifier">str</span><span class="special">,</span><span class="keyword"> int</span><span class="identifier"> start</span><span class="special">,</span><span class="identifier"> PyObject</span><span class="special"> *</span><span class="identifier">globals</span><span class="special">,</span><span class="identifier"> PyObject</span><span class="special"> *</span><span class="identifier">locals</span><span class="special">)</span></tt></pre><p><a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55" target="_top">
PyRun_String</a> takes the code to execute as a null-terminated (C-style)
string in its <tt class="literal">str</tt> parameter. The function returns a new reference to a
Python object. Which object is returned depends on the <tt class="literal">start</tt> paramater.</p><p>
The <tt class="literal">start</tt> parameter is the start symbol from the Python grammar to use
for interpreting the code. The possible values are:</p><div class="informaltable"><h4><a name="id416459"></a><span class="table-title">Start symbols</span></h4><table class="table"><colgroup><col><col></colgroup><tbody><tr><td><a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-58" target="_top">
Py_eval_input</a></td><td>for interpreting isolated expressions</td></tr><tr><td><a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-59" target="_top">
Py_file_input</a></td><td>for interpreting sequences of statements</td></tr><tr><td><a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-60" target="_top">
Py_single_input</a></td><td>for interpreting a single statement</td></tr></tbody></table></div><p>
When using <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-58" target="_top">
Py_eval_input</a>, the input string must contain a single expression
and its result is returned. When using <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-59" target="_top">
Py_file_input</a>, the string can
contain an abitrary number of statements and None is returned.
<a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-60" target="_top">
Py_single_input</a> works in the same way as <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-59" target="_top">
Py_file_input</a> but only accepts a
single statement.</p><p>
Lastly, the <tt class="literal">globals</tt> and <tt class="literal">locals</tt> 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
<tt class="literal">__main__</tt> module for both parameters.</p><p>
We have already seen how to get the <tt class="literal">__main__</tt> module's namespace so let's
run some Python code in it:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> object</span><span class="identifier"> main_module</span><span class="special">((</span><span class="identifier">
handle</span><span class="special">&lt;&gt;(</span><span class="identifier">borrowed</span><span class="special">(</span><span class="identifier">PyImport_AddModule</span><span class="special">(</span><span class="string">"__main__"</span><span class="special">)))));</span><span class="identifier">
object</span><span class="identifier"> main_namespace</span><span class="special"> =</span><span class="identifier"> main_module</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"__dict__"</span><span class="special">);</span><span class="identifier">
handle</span><span class="special">&lt;&gt;</span><span class="identifier"> ignored</span><span class="special">((</span><span class="identifier">PyRun_String</span><span class="special">(</span><span class="string">
"hello = file('hello.txt', 'w')\n"</span><span class="string">
"hello.write('Hello world!')\n"</span><span class="string">
"hello.close()"</span><span class="special">
,</span><span class="identifier"> Py_file_input</span><span class="special">
,</span><span class="identifier"> main_namespace</span><span class="special">.</span><span class="identifier">ptr</span><span class="special">()</span><span class="special">
,</span><span class="identifier"> main_namespace</span><span class="special">.</span><span class="identifier">ptr</span><span class="special">())</span><span class="special">
));</span></tt></pre><p>
Because the Python/C API doesn't know anything about <tt class="literal">object</tt>s, we used
the object's <tt class="literal">ptr</tt> member function to retrieve the <tt class="literal">PyObject*</tt>.</p><p>
This should create a file called 'hello.txt' in the current directory
containing a phrase that is well-known in programming circles.</p><p><span class="inlinemediaobject"><img src="images/note.gif"></span><span class="bold"><b>Note</b></span> that we wrap the return value of <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55" target="_top">
PyRun_String</a> in a
(nameless) <tt class="literal">handle</tt> 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 <tt class="literal">PyObject*</tt>s in <tt class="literal">handle</tt>s.</p><a name="using_the_interpreter.beyond_handles"></a><h2><a name="id416883"></a>Beyond handles</h2><p>
It's nice that <tt class="literal">handle</tt> 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 <a href="object_interface.html" target="_top">
previous section</a>: the aptly
named <tt class="literal">object</tt> class and it's derivatives. We've already seen that they
can be constructed from a <tt class="literal">handle</tt>. The following examples should further
illustrate this fact:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> object</span><span class="identifier"> main_module</span><span class="special">((</span><span class="identifier">
handle</span><span class="special">&lt;&gt;(</span><span class="identifier">borrowed</span><span class="special">(</span><span class="identifier">PyImport_AddModule</span><span class="special">(</span><span class="string">"__main__"</span><span class="special">)))));</span><span class="identifier">
object</span><span class="identifier"> main_namespace</span><span class="special"> =</span><span class="identifier"> main_module</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"__dict__"</span><span class="special">);</span><span class="identifier">
handle</span><span class="special">&lt;&gt;</span><span class="identifier"> ignored</span><span class="special">((</span><span class="identifier">PyRun_String</span><span class="special">(</span><span class="string">
"result = 5 ** 2"</span><span class="special">
,</span><span class="identifier"> Py_file_input</span><span class="special">
,</span><span class="identifier"> main_namespace</span><span class="special">.</span><span class="identifier">ptr</span><span class="special">()</span><span class="special">
,</span><span class="identifier"> main_namespace</span><span class="special">.</span><span class="identifier">ptr</span><span class="special">())</span><span class="special">
));</span><span class="keyword">
int</span><span class="identifier"> five_squared</span><span class="special"> =</span><span class="identifier"> extract</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;(</span><span class="identifier">main_namespace</span><span class="special">[</span><span class="string">"result"</span><span class="special">]);</span></tt></pre><p>
Here we create a dictionary object for the <tt class="literal">__main__</tt> 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
<a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55" target="_top">
PyRun_String</a> return the result directly with <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-58" target="_top">
Py_eval_input</a>:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> object</span><span class="identifier"> result</span><span class="special">((</span><span class="identifier">handle</span><span class="special">&lt;&gt;(</span><span class="identifier">
PyRun_String</span><span class="special">(</span><span class="string">"5 ** 2"</span><span class="special">
,</span><span class="identifier"> Py_eval_input</span><span class="special">
,</span><span class="identifier"> main_namespace</span><span class="special">.</span><span class="identifier">ptr</span><span class="special">()</span><span class="special">
,</span><span class="identifier"> main_namespace</span><span class="special">.</span><span class="identifier">ptr</span><span class="special">()))</span><span class="special">
));</span><span class="keyword">
int</span><span class="identifier"> five_squared</span><span class="special"> =</span><span class="identifier"> extract</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;(</span><span class="identifier">result</span><span class="special">);</span></tt></pre><p><span class="inlinemediaobject"><img src="images/note.gif"></span><span class="bold"><b>Note</b></span> that <tt class="literal">object</tt>'s member function to return the wrapped
<tt class="literal">PyObject*</tt> is called <tt class="literal">ptr</tt> instead of <tt class="literal">get</tt>. This makes sense if you
take into account the different functions that <tt class="literal">object</tt> and <tt class="literal">handle</tt>
perform.</p><a name="using_the_interpreter.exception_handling"></a><h2><a name="id417441"></a>Exception handling</h2><p>
If an exception occurs in the execution of some Python code, the <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55" target="_top">
PyRun_String</a> function returns a null pointer. Constructing a <tt class="literal">handle</tt> out of this null pointer throws <a href="../../v2/errors.html#error_already_set-spec" target="_top">
error_already_set</a>, so basically, the Python exception is automatically translated into a C++ exception when using <tt class="literal">handle</tt>:</p><pre class="programlisting"><tt class="literal"><span class="keyword"> try</span><span class="special">
{</span><span class="identifier">
object</span><span class="identifier"> result</span><span class="special">((</span><span class="identifier">handle</span><span class="special">&lt;&gt;(</span><span class="identifier">PyRun_String</span><span class="special">(</span><span class="string">
"5/0"</span><span class="special">
,</span><span class="identifier"> Py_eval_input</span><span class="special">
,</span><span class="identifier"> main_namespace</span><span class="special">.</span><span class="identifier">ptr</span><span class="special">()</span><span class="special">
,</span><span class="identifier"> main_namespace</span><span class="special">.</span><span class="identifier">ptr</span><span class="special">()))</span><span class="special">
));</span><span class="comment">
// execution will never get here:
</span><span class="keyword"> int</span><span class="identifier"> five_divided_by_zero</span><span class="special"> =</span><span class="identifier"> extract</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;(</span><span class="identifier">result</span><span class="special">);</span><span class="special">
}</span><span class="keyword">
catch</span><span class="special">(</span><span class="identifier">error_already_set</span><span class="special">)</span><span class="special">
{</span><span class="comment">
// handle the exception in some way
</span><span class="special"> }</span></tt></pre><p>
The <tt class="literal">error_already_set</tt> exception class doesn't carry any information in itself. To find out more about the Python exception that occurred, you need to use the <a href="http://www.python.org/doc/api/exceptionHandling.html" target="_top">
exception handling functions</a> of the Python/C API in your catch-statement. This can be as simple as calling <a href="http://www.python.org/doc/api/exceptionHandling.html#l2h-70" target="_top">
PyErr_Print()</a> to print the exception's traceback to the console, or comparing the type of the exception with those of the <a href="http://www.python.org/doc/api/standardExceptions.html" target="_top">
standard exceptions</a>:</p><pre class="programlisting"><tt class="literal"><span class="keyword"> catch</span><span class="special">(</span><span class="identifier">error_already_set</span><span class="special">)</span><span class="special">
{</span><span class="keyword">
if</span><span class="special"> (</span><span class="identifier">PyErr_ExceptionMatches</span><span class="special">(</span><span class="identifier">PyExc_ZeroDivisionError</span><span class="special">))</span><span class="special">
{</span><span class="comment">
// handle ZeroDivisionError specially
</span><span class="special"> }</span><span class="keyword">
else</span><span class="special">
{</span><span class="comment">
// print all other errors to stderr
</span><span class="identifier"> PyErr_Print</span><span class="special">();</span><span class="special">
}</span><span class="special">
}</span></tt></pre><p>
(To retrieve even more information from the exception you can use some of the other exception handling functions listed <a href="http://www.python.org/doc/api/exceptionHandling.html" target="_top">
here</a>.)</p><p>
If you'd rather not have <tt class="literal">handle</tt> throw a C++ exception when it is constructed, you can use the <a href="../../v2/handle.html#allow_null-spec" target="_top">
allow_null</a> function in the same way you'd use borrowed:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> handle</span><span class="special">&lt;&gt;</span><span class="identifier"> result</span><span class="special">((</span><span class="identifier">allow_null</span><span class="special">(</span><span class="identifier">PyRun_String</span><span class="special">(</span><span class="string">
"5/0"</span><span class="special">
,</span><span class="identifier"> Py_eval_input</span><span class="special">
,</span><span class="identifier"> main_namespace</span><span class="special">.</span><span class="identifier">ptr</span><span class="special">()</span><span class="special">
,</span><span class="identifier"> main_namespace</span><span class="special">.</span><span class="identifier">ptr</span><span class="special">()))));</span><span class="keyword">
if</span><span class="special"> (!</span><span class="identifier">result</span><span class="special">)</span><span class="comment">
// Python exception occurred
</span><span class="keyword"> else</span><span class="comment">
// everything went okay, it's safe to use the result
</span></tt></pre></div></div><table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr><td align="left"></td><td align="right"><small>Copyright © 2002-2004 Joel de Guzman, David Abrahams</small></td></tr></table><hr><div class="spirit-nav"><a accesskey="p" href="boost_python.object.html"><img src="images/prev.png" alt="Prev"></a><a accesskey="u" href="index.html"><img src="images/up.png" alt="Up"></a><a accesskey="h" href="index.html"><img src="images/home.png" alt="Home"></a><a accesskey="n" href="boost_python.iterators.html"><img src="images/next.png" alt="Next"></a></div></body></html>

View File

@@ -1,13 +0,0 @@
<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title> Exception Translation</title><link rel="stylesheet" href="boostbook.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="Chapter 1. Boost.Boost Python 1.0"><link rel="up" href="index.html" title="Chapter 1. Boost.Boost Python 1.0"><link rel="previous" href="boost_python.iterators.html" title="Iterators"><link rel="next" href="boost_python.techniques.html" title=" General Techniques"><link rel="chapter" href="index.html" title="Chapter 1. Boost.Boost Python 1.0"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><table cellpadding="2" width="100%"><td valign="top"><img src="../../../../../../boost.png" alt="boost.png (6897 bytes)" width="277" height="86"></td><td align="center"><a href="../../index.htm">Home</a></td><td align="center"><a href="libraries.html">Libraries</a></td><td align="center"><a href="../../people/people.htm">People</a></td><td align="center"><a href="../../more/faq.htm">FAQ</a></td><td align="center"><a href="../../more/index.htm">More</a></td></table><hr><div class="spirit-nav"><a accesskey="p" href="boost_python.iterators.html"><img src="images/prev.png" alt="Prev"></a><a accesskey="u" href="index.html"><img src="images/up.png" alt="Up"></a><a accesskey="h" href="index.html"><img src="images/home.png" alt="Home"></a><a accesskey="n" href="boost_python.techniques.html"><img src="images/next.png" alt="Next"></a></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="boost_python.exception"></a> Exception Translation</h2></div></div><div></div></div><p>
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:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> raise</span><span class="identifier"> RuntimeError</span><span class="special">,</span><span class="char"> 'unidentifiable C++ Exception'</span></tt></pre><p>
Users may provide custom translation. Here's an example:</p><pre class="programlisting"><tt class="literal"><span class="keyword"> struct</span><span class="identifier"> PodBayDoorException</span><span class="special">;</span><span class="keyword">
void</span><span class="identifier"> translator</span><span class="special">(</span><span class="identifier">PodBayDoorException</span><span class="keyword"> const</span><span class="special">&amp;</span><span class="identifier"> x</span><span class="special">)</span><span class="special"> {</span><span class="identifier">
PyErr_SetString</span><span class="special">(</span><span class="identifier">PyExc_UserWarning</span><span class="special">,</span><span class="string"> "I'm sorry Dave..."</span><span class="special">);</span><span class="special">
}</span><span class="identifier">
BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">kubrick</span><span class="special">)</span><span class="special"> {</span><span class="identifier">
register_exception_translator</span><span class="special">&lt;</span><span class="identifier">
PodBayDoorException</span><span class="special">&gt;(</span><span class="identifier">translator</span><span class="special">);</span><span class="special">
...</span></tt></pre></div><table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr><td align="left"></td><td align="right"><small>Copyright © 2002-2004 Joel de Guzman, David Abrahams</small></td></tr></table><hr><div class="spirit-nav"><a accesskey="p" href="boost_python.iterators.html"><img src="images/prev.png" alt="Prev"></a><a accesskey="u" href="index.html"><img src="images/up.png" alt="Up"></a><a accesskey="h" href="index.html"><img src="images/home.png" alt="Home"></a><a accesskey="n" href="boost_python.techniques.html"><img src="images/next.png" alt="Next"></a></div></body></html>

View File

@@ -1,326 +0,0 @@
<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title> Exposing Classes</title><link rel="stylesheet" href="boostbook.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="Chapter 1. Boost.Boost Python 1.0"><link rel="up" href="index.html" title="Chapter 1. Boost.Boost Python 1.0"><link rel="previous" href="boost_python.hello.html" title=" Building Hello World"><link rel="next" href="boost_python.functions.html" title="Functions"><link rel="chapter" href="index.html" title="Chapter 1. Boost.Boost Python 1.0"><link rel="subsection" href="boost_python.exposing.html#boost_python.constructors" title="Constructors"><link rel="subsection" href="boost_python.exposing.html#boost_python.class_data_members" title="Class Data Members"><link rel="subsection" href="boost_python.exposing.html#boost_python.class_properties" title="Class Properties"><link rel="subsection" href="boost_python.exposing.html#boost_python.inheritance" title="Inheritance"><link rel="subsection" href="boost_python.exposing.html#boost_python.class_virtual_functions" title="Class Virtual Functions"><link rel="subsection" href="boost_python.exposing.html#boost_python.deriving_a_python_class" title="Deriving a Python Class"><link rel="subsection" href="boost_python.exposing.html#boost_python.virtual_functions_with_default_implementations" title="Virtual Functions with Default Implementations"><link rel="subsection" href="boost_python.exposing.html#boost_python.class_operators_special_functions" title="Class Operators/Special Functions"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><table cellpadding="2" width="100%"><td valign="top"><img src="../../../../../../boost.png" alt="boost.png (6897 bytes)" width="277" height="86"></td><td align="center"><a href="../../index.htm">Home</a></td><td align="center"><a href="libraries.html">Libraries</a></td><td align="center"><a href="../../people/people.htm">People</a></td><td align="center"><a href="../../more/faq.htm">FAQ</a></td><td align="center"><a href="../../more/index.htm">More</a></td></table><hr><div class="spirit-nav"><a accesskey="p" href="boost_python.hello.html"><img src="images/prev.png" alt="Prev"></a><a accesskey="u" href="index.html"><img src="images/up.png" alt="Up"></a><a accesskey="h" href="index.html"><img src="images/home.png" alt="Home"></a><a accesskey="n" href="boost_python.functions.html"><img src="images/next.png" alt="Next"></a></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="boost_python.exposing"></a> Exposing Classes</h2></div></div><div></div></div><div class="toc"><dl><dt><span class="section"><a href="boost_python.exposing.html#boost_python.constructors">Constructors</a></span></dt><dt><span class="section"><a href="boost_python.exposing.html#boost_python.class_data_members">Class Data Members</a></span></dt><dt><span class="section"><a href="boost_python.exposing.html#boost_python.class_properties">Class Properties</a></span></dt><dt><span class="section"><a href="boost_python.exposing.html#boost_python.inheritance">Inheritance</a></span></dt><dt><span class="section"><a href="boost_python.exposing.html#boost_python.class_virtual_functions">Class Virtual Functions</a></span></dt><dt><span class="section"><a href="boost_python.exposing.html#boost_python.deriving_a_python_class">Deriving a Python Class</a></span></dt><dt><span class="section"><a href="boost_python.exposing.html#boost_python.virtual_functions_with_default_implementations">Virtual Functions with Default Implementations</a></span></dt><dt><span class="section"><a href="boost_python.exposing.html#boost_python.class_operators_special_functions">Class Operators/Special Functions</a></span></dt></dl></div><p>
Now let's expose a C++ class to Python.</p><p>
Consider a C++ class/struct that we want to expose to Python:</p><pre class="programlisting"><tt class="literal"><span class="keyword"> struct</span><span class="identifier"> World</span><span class="special">
{</span><span class="keyword">
void</span><span class="identifier"> set</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="identifier"> msg</span><span class="special">)</span><span class="special"> {</span><span class="keyword"> this</span><span class="special">-&gt;</span><span class="identifier">msg</span><span class="special"> =</span><span class="identifier"> msg</span><span class="special">;</span><span class="special"> }</span><span class="identifier">
std</span><span class="special">::</span><span class="identifier">string</span><span class="identifier"> greet</span><span class="special">()</span><span class="special"> {</span><span class="keyword"> return</span><span class="identifier"> msg</span><span class="special">;</span><span class="special"> }</span><span class="identifier">
std</span><span class="special">::</span><span class="identifier">string</span><span class="identifier"> msg</span><span class="special">;</span><span class="special">
};</span></tt></pre><p>
We can expose this to Python by writing a corresponding Boost.Python
C++ Wrapper:</p><pre class="programlisting"><tt class="literal"><span class="preprocessor"> #include</span><span class="special"> &lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">python</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span><span class="keyword">
using</span><span class="keyword"> namespace</span><span class="identifier"> boost</span><span class="special">::</span><span class="identifier">python</span><span class="special">;</span><span class="identifier">
BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">hello</span><span class="special">)</span><span class="special">
{</span><span class="identifier">
class_</span><span class="special">&lt;</span><span class="identifier">World</span><span class="special">&gt;(</span><span class="string">"World"</span><span class="special">)</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"greet"</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">World</span><span class="special">::</span><span class="identifier">greet</span><span class="special">)</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"set"</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">World</span><span class="special">::</span><span class="identifier">set</span><span class="special">)</span><span class="special">
;</span><span class="special">
}</span></tt></pre><p>
Here, we wrote a C++ class wrapper that exposes the member functions
<tt class="literal">greet</tt> and <tt class="literal">set</tt>. Now, after building our module as a shared library, we
may use our class <tt class="literal">World</tt> in Python. Here's a sample Python session:</p><pre class="programlisting"><tt class="literal"><span class="special"> &gt;&gt;&gt;</span><span class="identifier"> import</span><span class="identifier"> hello</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> planet</span><span class="special"> =</span><span class="identifier"> hello</span><span class="special">.</span><span class="identifier">World</span><span class="special">()</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> planet</span><span class="special">.</span><span class="identifier">set</span><span class="special">(</span><span class="char">'howdy'</span><span class="special">)</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> planet</span><span class="special">.</span><span class="identifier">greet</span><span class="special">()</span><span class="char">
'howdy'</span></tt></pre><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="boost_python.constructors"></a>Constructors</h3></div></div><div></div></div><p>
Our previous example didn't have any explicit constructors.
Since <tt class="literal">World</tt> 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</p><pre class="programlisting"><tt class="literal"><span class="special"> &gt;&gt;&gt;</span><span class="identifier"> planet</span><span class="special"> =</span><span class="identifier"> hello</span><span class="special">.</span><span class="identifier">World</span><span class="special">()</span></tt></pre><p>
We may wish to wrap a class with a non-default constructor. Let us
build on our previous example:</p><pre class="programlisting"><tt class="literal"><span class="keyword"> struct</span><span class="identifier"> World</span><span class="special">
{</span><span class="identifier">
World</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="identifier"> msg</span><span class="special">):</span><span class="identifier"> msg</span><span class="special">(</span><span class="identifier">msg</span><span class="special">)</span><span class="special"> {}</span><span class="comment"> // added constructor
</span><span class="keyword"> void</span><span class="identifier"> set</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="identifier"> msg</span><span class="special">)</span><span class="special"> {</span><span class="keyword"> this</span><span class="special">-&gt;</span><span class="identifier">msg</span><span class="special"> =</span><span class="identifier"> msg</span><span class="special">;</span><span class="special"> }</span><span class="identifier">
std</span><span class="special">::</span><span class="identifier">string</span><span class="identifier"> greet</span><span class="special">()</span><span class="special"> {</span><span class="keyword"> return</span><span class="identifier"> msg</span><span class="special">;</span><span class="special"> }</span><span class="identifier">
std</span><span class="special">::</span><span class="identifier">string</span><span class="identifier"> msg</span><span class="special">;</span><span class="special">
};</span></tt></pre><p>
This time <tt class="literal">World</tt> has no default constructor; our previous
wrapping code would fail to compile when the library tried to expose
it. We have to tell <tt class="literal">class_&lt;World&gt;</tt> about the constructor we want to
expose instead.</p><pre class="programlisting"><tt class="literal"><span class="preprocessor"> #include</span><span class="special"> &lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">python</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span><span class="keyword">
using</span><span class="keyword"> namespace</span><span class="identifier"> boost</span><span class="special">::</span><span class="identifier">python</span><span class="special">;</span><span class="identifier">
BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">hello</span><span class="special">)</span><span class="special">
{</span><span class="identifier">
class_</span><span class="special">&lt;</span><span class="identifier">World</span><span class="special">&gt;(</span><span class="string">"World"</span><span class="special">,</span><span class="identifier"> init</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&gt;())</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"greet"</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">World</span><span class="special">::</span><span class="identifier">greet</span><span class="special">)</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"set"</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">World</span><span class="special">::</span><span class="identifier">set</span><span class="special">)</span><span class="special">
;</span><span class="special">
}</span></tt></pre><p><tt class="literal">init&lt;std::string&gt;()</tt> exposes the constructor taking in a
<tt class="literal">std::string</tt> (in Python, constructors are spelled
"<tt class="literal">"__init__"</tt>").</p><p>
We can expose additional constructors by passing more <tt class="literal">init&lt;...&gt;</tt>s to
the <tt class="literal">def()</tt> member function. Say for example we have another World
constructor taking in two doubles:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> class_</span><span class="special">&lt;</span><span class="identifier">World</span><span class="special">&gt;(</span><span class="string">"World"</span><span class="special">,</span><span class="identifier"> init</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&gt;())</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">init</span><span class="special">&lt;</span><span class="keyword">double</span><span class="special">,</span><span class="keyword"> double</span><span class="special">&gt;())</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"greet"</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">World</span><span class="special">::</span><span class="identifier">greet</span><span class="special">)</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"set"</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">World</span><span class="special">::</span><span class="identifier">set</span><span class="special">)</span><span class="special">
;</span></tt></pre><p>
On the other hand, if we do not wish to expose any constructors at
all, we may use <tt class="literal">no_init</tt> instead:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> class_</span><span class="special">&lt;</span><span class="identifier">Abstract</span><span class="special">&gt;(</span><span class="string">"Abstract"</span><span class="special">,</span><span class="identifier"> no_init</span><span class="special">)</span></tt></pre><p>
This actually adds an <tt class="literal">__init__</tt> method which always raises a
Python RuntimeError exception.</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="boost_python.class_data_members"></a>Class Data Members</h3></div></div><div></div></div><p>
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 <span class="bold"><b>read-only</b></span> or
<span class="bold"><b>read-write</b></span>. Consider this class <tt class="literal">Var</tt>:</p><pre class="programlisting"><tt class="literal"><span class="keyword"> struct</span><span class="identifier"> Var</span><span class="special">
{</span><span class="identifier">
Var</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="identifier"> name</span><span class="special">)</span><span class="special"> :</span><span class="identifier"> name</span><span class="special">(</span><span class="identifier">name</span><span class="special">),</span><span class="identifier"> value</span><span class="special">()</span><span class="special"> {}</span><span class="identifier">
std</span><span class="special">::</span><span class="identifier">string</span><span class="keyword"> const</span><span class="identifier"> name</span><span class="special">;</span><span class="keyword">
float</span><span class="identifier"> value</span><span class="special">;</span><span class="special">
};</span></tt></pre><p>
Our C++ <tt class="literal">Var</tt> class and its data members can be exposed to Python:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> class_</span><span class="special">&lt;</span><span class="identifier">Var</span><span class="special">&gt;(</span><span class="string">"Var"</span><span class="special">,</span><span class="identifier"> init</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&gt;())</span><span class="special">
.</span><span class="identifier">def_readonly</span><span class="special">(</span><span class="string">"name"</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">Var</span><span class="special">::</span><span class="identifier">name</span><span class="special">)</span><span class="special">
.</span><span class="identifier">def_readwrite</span><span class="special">(</span><span class="string">"value"</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">Var</span><span class="special">::</span><span class="identifier">value</span><span class="special">);</span></tt></pre><p>
Then, in Python, assuming we have placed our Var class inside the namespace
hello as we did before:</p><pre class="programlisting"><tt class="literal"><span class="special"> &gt;&gt;&gt;</span><span class="identifier"> x</span><span class="special"> =</span><span class="identifier"> hello</span><span class="special">.</span><span class="identifier">Var</span><span class="special">(</span><span class="char">'pi'</span><span class="special">)</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> x</span><span class="special">.</span><span class="identifier">value</span><span class="special"> =</span><span class="number"> 3.14</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> print</span><span class="identifier"> x</span><span class="special">.</span><span class="identifier">name</span><span class="special">,</span><span class="char"> 'is around'</span><span class="special">,</span><span class="identifier"> x</span><span class="special">.</span><span class="identifier">value</span><span class="identifier">
pi</span><span class="identifier"> is</span><span class="identifier"> around</span><span class="number"> 3.14</span></tt></pre><p>
Note that <tt class="literal">name</tt> is exposed as <span class="bold"><b>read-only</b></span> while <tt class="literal">value</tt> is exposed
as <span class="bold"><b>read-write</b></span>.</p><pre class="programlisting"><tt class="literal"> &gt;&gt;&gt; x.name = 'e' # can't change name
Traceback (most recent call last):
File "&lt;stdin&gt;", line 1, in ?
AttributeError: can't set attribute
</tt></pre></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="boost_python.class_properties"></a>Class Properties</h3></div></div><div></div></div><p>
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:</p><pre class="programlisting"><tt class="literal"><span class="keyword"> struct</span><span class="identifier"> Num</span><span class="special">
{</span><span class="identifier">
Num</span><span class="special">();</span><span class="keyword">
float</span><span class="identifier"> get</span><span class="special">()</span><span class="keyword"> const</span><span class="special">;</span><span class="keyword">
void</span><span class="identifier"> set</span><span class="special">(</span><span class="keyword">float</span><span class="identifier"> value</span><span class="special">);</span><span class="special">
...</span><span class="special">
};</span></tt></pre><p>
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
<tt class="literal">Num</tt> class using Boost.Python:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> class_</span><span class="special">&lt;</span><span class="identifier">Num</span><span class="special">&gt;(</span><span class="string">"Num"</span><span class="special">)</span><span class="special">
.</span><span class="identifier">add_property</span><span class="special">(</span><span class="string">"rovalue"</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">Num</span><span class="special">::</span><span class="identifier">get</span><span class="special">)</span><span class="special">
.</span><span class="identifier">add_property</span><span class="special">(</span><span class="string">"value"</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">Num</span><span class="special">::</span><span class="identifier">get</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">Num</span><span class="special">::</span><span class="identifier">set</span><span class="special">);</span></tt></pre><p>
And at last, in Python:</p><pre class="programlisting"><tt class="literal"><span class="special"> &gt;&gt;&gt;</span><span class="identifier"> x</span><span class="special"> =</span><span class="identifier"> Num</span><span class="special">()</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> x</span><span class="special">.</span><span class="identifier">value</span><span class="special"> =</span><span class="number"> 3.14</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> x</span><span class="special">.</span><span class="identifier">value</span><span class="special">,</span><span class="identifier"> x</span><span class="special">.</span><span class="identifier">rovalue</span><span class="special">
(</span><span class="number">3.14</span><span class="special">,</span><span class="number"> 3.14</span><span class="special">)</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> x</span><span class="special">.</span><span class="identifier">rovalue</span><span class="special"> =</span><span class="number"> 2.17</span>#<span class="identifier"> error</span><span class="special">!</span></tt></pre><p>
Take note that the class property <tt class="literal">rovalue</tt> is exposed as <span class="bold"><b>read-only</b></span>
since the <tt class="literal">rovalue</tt> setter member function is not passed in:</p><pre class="programlisting"><tt class="literal"><span class="special"> .</span><span class="identifier">add_property</span><span class="special">(</span><span class="string">"rovalue"</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">Num</span><span class="special">::</span><span class="identifier">get</span><span class="special">)</span></tt></pre></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="boost_python.inheritance"></a>Inheritance</h3></div></div><div></div></div><p>
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.</p><p>
Consider this trivial inheritance structure:</p><pre class="programlisting"><tt class="literal"><span class="keyword"> struct</span><span class="identifier"> Base</span><span class="special"> {</span><span class="keyword"> virtual</span><span class="special"> ~</span><span class="identifier">Base</span><span class="special">();</span><span class="special"> };</span><span class="keyword">
struct</span><span class="identifier"> Derived</span><span class="special"> :</span><span class="identifier"> Base</span><span class="special"> {};</span></tt></pre><p>
And a set of C++ functions operating on <tt class="literal">Base</tt> and <tt class="literal">Derived</tt> object
instances:</p><pre class="programlisting"><tt class="literal"><span class="keyword"> void</span><span class="identifier"> b</span><span class="special">(</span><span class="identifier">Base</span><span class="special">*);</span><span class="keyword">
void</span><span class="identifier"> d</span><span class="special">(</span><span class="identifier">Derived</span><span class="special">*);</span><span class="identifier">
Base</span><span class="special">*</span><span class="identifier"> factory</span><span class="special">()</span><span class="special"> {</span><span class="keyword"> return</span><span class="keyword"> new</span><span class="identifier"> Derived</span><span class="special">;</span><span class="special"> }</span></tt></pre><p>
We've seen how we can wrap the base class <tt class="literal">Base</tt>:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> class_</span><span class="special">&lt;</span><span class="identifier">Base</span><span class="special">&gt;(</span><span class="string">"Base"</span><span class="special">)</span><span class="comment">
/*...*/</span><span class="special">
;</span></tt></pre><p>
Now we can inform Boost.Python of the inheritance relationship between
<tt class="literal">Derived</tt> and its base class <tt class="literal">Base</tt>. Thus:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> class_</span><span class="special">&lt;</span><span class="identifier">Derived</span><span class="special">,</span><span class="identifier"> bases</span><span class="special">&lt;</span><span class="identifier">Base</span><span class="special">&gt;</span><span class="special"> &gt;(</span><span class="string">"Derived"</span><span class="special">)</span><span class="comment">
/*...*/</span><span class="special">
;</span></tt></pre><p>
Doing so, we get some things for free:</p><div class="orderedlist"><ol type="1"><li>
Derived automatically inherits all of Base's Python methods (wrapped C++ member functions)
</li><li><span class="bold"><b>If</b></span> Base is polymorphic, <tt class="literal">Derived</tt> objects which have been passed to Python via a pointer or reference to <tt class="literal">Base</tt> can be passed where a pointer or reference to <tt class="literal">Derived</tt> is expected.
</li></ol></div><p>
Now, we shall expose the C++ free functions <tt class="literal">b</tt> and <tt class="literal">d</tt> and <tt class="literal">factory</tt>:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> def</span><span class="special">(</span><span class="string">"b"</span><span class="special">,</span><span class="identifier"> b</span><span class="special">);</span><span class="identifier">
def</span><span class="special">(</span><span class="string">"d"</span><span class="special">,</span><span class="identifier"> d</span><span class="special">);</span><span class="identifier">
def</span><span class="special">(</span><span class="string">"factory"</span><span class="special">,</span><span class="identifier"> factory</span><span class="special">);</span></tt></pre><p>
Note that free function <tt class="literal">factory</tt> is being used to generate new
instances of class <tt class="literal">Derived</tt>. In such cases, we use
<tt class="literal">return_value_policy&lt;manage_new_object&gt;</tt> to instruct Python to adopt
the pointer to <tt class="literal">Base</tt> and hold the instance in a new Python <tt class="literal">Base</tt>
object until the the Python object is destroyed. We shall see more of
Boost.Python <a href="call_policies.html" target="_top">
call policies</a> later.</p><pre class="programlisting"><tt class="literal"><span class="comment"> // Tell Python to take ownership of factory's result
</span><span class="identifier"> def</span><span class="special">(</span><span class="string">"factory"</span><span class="special">,</span><span class="identifier"> factory</span><span class="special">,</span><span class="identifier">
return_value_policy</span><span class="special">&lt;</span><span class="identifier">manage_new_object</span><span class="special">&gt;());</span></tt></pre></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="boost_python.class_virtual_functions"></a>Class Virtual Functions</h3></div></div><div></div></div><p>
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 <tt class="literal">Base</tt> class:</p><pre class="programlisting"><tt class="literal"><span class="keyword"> struct</span><span class="identifier"> Base</span><span class="special">
{</span><span class="keyword">
virtual</span><span class="keyword"> int</span><span class="identifier"> f</span><span class="special">()</span><span class="special"> =</span><span class="number"> 0</span><span class="special">;</span><span class="special">
};</span></tt></pre><p>
Since <tt class="literal">f</tt> is a pure virtual function, <tt class="literal">Base</tt> is now an abstract
class. Given an instance of our class, the free function <tt class="literal">call_f</tt>
calls some implementation of this virtual function in a concrete
derived class:</p><pre class="programlisting"><tt class="literal"><span class="keyword"> int</span><span class="identifier"> call_f</span><span class="special">(</span><span class="identifier">Base</span><span class="special">&amp;</span><span class="identifier"> b</span><span class="special">)</span><span class="special"> {</span><span class="keyword"> return</span><span class="identifier"> b</span><span class="special">.</span><span class="identifier">f</span><span class="special">();</span><span class="special"> }</span></tt></pre><p>
To allow this function to be implemented in a Python derived class, we
need to create a class wrapper:</p><pre class="programlisting"><tt class="literal"><span class="keyword"> struct</span><span class="identifier"> BaseWrap</span><span class="special"> :</span><span class="identifier"> Base</span><span class="special">
{</span><span class="identifier">
BaseWrap</span><span class="special">(</span><span class="identifier">PyObject</span><span class="special">*</span><span class="identifier"> self_</span><span class="special">)</span><span class="special">
:</span><span class="identifier"> self</span><span class="special">(</span><span class="identifier">self_</span><span class="special">)</span><span class="special"> {}</span><span class="keyword">
int</span><span class="identifier"> f</span><span class="special">()</span><span class="special"> {</span><span class="keyword"> return</span><span class="identifier"> call_method</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;(</span><span class="identifier">self</span><span class="special">,</span><span class="string"> "f"</span><span class="special">);</span><span class="special"> }</span><span class="identifier">
PyObject</span><span class="special">*</span><span class="identifier"> self</span><span class="special">;</span><span class="special">
};</span><span class="keyword">
struct</span><span class="identifier"> BaseWrap</span><span class="special"> :</span><span class="identifier"> Base</span><span class="special">
{</span><span class="identifier">
BaseWrap</span><span class="special">(</span><span class="identifier">PyObject</span><span class="special">*</span><span class="identifier"> self_</span><span class="special">)</span><span class="special">
:</span><span class="identifier"> self</span><span class="special">(</span><span class="identifier">self_</span><span class="special">)</span><span class="special"> {}</span><span class="identifier">
BaseWrap</span><span class="special">(</span><span class="identifier">PyObject</span><span class="special">*</span><span class="identifier"> self_</span><span class="special">,</span><span class="identifier"> Base</span><span class="keyword"> const</span><span class="special">&amp;</span><span class="identifier"> copy</span><span class="special">)</span><span class="special">
:</span><span class="identifier"> Base</span><span class="special">(</span><span class="identifier">copy</span><span class="special">),</span><span class="identifier"> self</span><span class="special">(</span><span class="identifier">self_</span><span class="special">)</span><span class="special"> {}</span><span class="keyword">
int</span><span class="identifier"> f</span><span class="special">()</span><span class="special"> {</span><span class="keyword"> return</span><span class="identifier"> call_method</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;(</span><span class="identifier">self</span><span class="special">,</span><span class="string"> "f"</span><span class="special">);</span><span class="special"> }</span><span class="keyword">
int</span><span class="identifier"> default_f</span><span class="special">()</span><span class="special"> {</span><span class="keyword"> return</span><span class="identifier"> Base</span><span class="special">::</span><span class="identifier">f</span><span class="special">();</span><span class="special"> }</span><span class="comment"> // &lt;&lt;=== ***ADDED***
</span><span class="identifier"> PyObject</span><span class="special">*</span><span class="identifier"> self</span><span class="special">;</span><span class="special">
};</span></tt></pre><div class="informaltable"><table class="table"><colgroup><col></colgroup><tbody><tr><td><span class="inlinemediaobject"><img src="images/lens.gif"></span><span class="bold"><b>member function and methods</b></span><p></p><p></p>
Python, like
many object oriented languages uses the term <span class="bold"><b>methods</b></span>. Methods
correspond roughly to C++'s <span class="bold"><b>member functions</b></span></td></tr></tbody></table></div><p>
Our class wrapper <tt class="literal">BaseWrap</tt> is derived from <tt class="literal">Base</tt>. Its overridden
virtual member function <tt class="literal">f</tt> in effect calls the corresponding method
of the Python object <tt class="literal">self</tt>, which is a pointer back to the Python
<tt class="literal">Base</tt> object holding our <tt class="literal">BaseWrap</tt> instance.</p><div class="informaltable"><table class="table"><colgroup><col></colgroup><tbody><tr><td><span class="inlinemediaobject"><img src="images/note.gif"></span><span class="bold"><b>Why do we need BaseWrap?</b></span><p></p><p></p></td></tr></tbody></table></div><p><span class="emphasis"><em>You may ask</em></span>, "Why do we need the <tt class="literal">BaseWrap</tt> derived class? This could
have been designed so that everything gets done right inside of
Base."</p><p></p><p></p><p>
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.</p><p></p><p></p><p>
Note however that you don't need to do this to get methods overridden
in Python to behave virtually when called <span class="emphasis"><em>from</em></span><span class="bold"><b>Python</b></span>. The only
time you need to do the <tt class="literal">BaseWrap</tt> dance is when you have a virtual
function that's going to be overridden in Python and called
polymorphically <span class="emphasis"><em>from</em></span><span class="bold"><b>C++</b></span>.]</p><p>
Wrapping <tt class="literal">Base</tt> and the free function <tt class="literal">call_f</tt>:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> class_</span><span class="special">&lt;</span><span class="identifier">Base</span><span class="special">,</span><span class="identifier"> BaseWrap</span><span class="special">,</span><span class="identifier"> boost</span><span class="special">::</span><span class="identifier">noncopyable</span><span class="special">&gt;(</span><span class="string">"Base"</span><span class="special">,</span><span class="identifier"> no_init</span><span class="special">)</span><span class="special">
;</span><span class="identifier">
def</span><span class="special">(</span><span class="string">"call_f"</span><span class="special">,</span><span class="identifier"> call_f</span><span class="special">);</span></tt></pre><p>
Notice that we parameterized the <tt class="literal">class_</tt> template with <tt class="literal">BaseWrap</tt> as the
second parameter. What is <tt class="literal">noncopyable</tt>? 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.</p><p>
In Python, let us try to instantiate our <tt class="literal">Base</tt> class:</p><pre class="programlisting"><tt class="literal"><span class="special"> &gt;&gt;&gt;</span><span class="identifier"> base</span><span class="special"> =</span><span class="identifier"> Base</span><span class="special">()</span><span class="identifier">
RuntimeError</span><span class="special">:</span><span class="identifier"> This</span><span class="keyword"> class</span><span class="identifier"> cannot</span><span class="identifier"> be</span><span class="identifier"> instantiated</span><span class="identifier"> from</span><span class="identifier"> Python</span></tt></pre><p>
Why is it an error? <tt class="literal">Base</tt> is an abstract class. As such it is advisable
to define the Python wrapper with <tt class="literal">no_init</tt> as we have done above. Doing
so will disallow abstract base classes such as <tt class="literal">Base</tt> to be instantiated.</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="boost_python.deriving_a_python_class"></a>Deriving a Python Class</h3></div></div><div></div></div><p>
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 <tt class="literal">class_</tt> wrapper as:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> class_</span><span class="special">&lt;</span><span class="identifier">Base</span><span class="special">,</span><span class="identifier"> BaseWrap</span><span class="special">,</span><span class="identifier"> boost</span><span class="special">::</span><span class="identifier">noncopyable</span><span class="special">&gt;(</span><span class="string">"Base"</span><span class="special">)</span><span class="special">
;</span></tt></pre><p>
Otherwise, we have to suppress the Base class' <tt class="literal">no_init</tt> by adding an
<tt class="literal">__init__()</tt> method to all our derived classes. <tt class="literal">no_init</tt> actually adds
an <tt class="literal">__init__</tt> method that raises a Python RuntimeError exception.</p><pre class="programlisting"><tt class="literal"><span class="special"> &gt;&gt;&gt;</span><span class="keyword"> class</span><span class="identifier"> Derived</span><span class="special">(</span><span class="identifier">Base</span><span class="special">):</span><span class="special">
...</span><span class="identifier"> def</span><span class="identifier"> f</span><span class="special">(</span><span class="identifier">self</span><span class="special">):</span><span class="special">
...</span><span class="keyword"> return</span><span class="number"> 42</span><span class="special">
...</span></tt></pre><p>
Cool eh? A Python class deriving from a C++ class!</p><p>
Let's now make an instance of our Python class <tt class="literal">Derived</tt>:</p><pre class="programlisting"><tt class="literal"><span class="special"> &gt;&gt;&gt;</span><span class="identifier"> derived</span><span class="special"> =</span><span class="identifier"> Derived</span><span class="special">()</span></tt></pre><p>
Calling <tt class="literal">derived.f()</tt>:</p><pre class="programlisting"><tt class="literal"><span class="special"> &gt;&gt;&gt;</span><span class="identifier"> derived</span><span class="special">.</span><span class="identifier">f</span><span class="special">()</span><span class="number">
42</span></tt></pre><p>
Will yield the expected result. Finally, calling calling the free function
<tt class="literal">call_f</tt> with <tt class="literal">derived</tt> as argument:</p><pre class="programlisting"><tt class="literal"><span class="special"> &gt;&gt;&gt;</span><span class="identifier"> call_f</span><span class="special">(</span><span class="identifier">derived</span><span class="special">)</span><span class="number">
42</span></tt></pre><p>
Will also yield the expected result.</p><p>
Here's what's happening:</p><div class="orderedlist"><ol type="1"><li><tt class="literal">call_f(derived)</tt> is called in Python
</li><li>
This corresponds to <tt class="literal">def("call_f", call_f);</tt>. Boost.Python dispatches this call.
</li><li><tt class="literal">int call_f(Base&amp; b) { return b.f(); }</tt> accepts the call.
</li><li>
The overridden virtual function <tt class="literal">f</tt> of <tt class="literal">BaseWrap</tt> is called.
</li><li><tt class="literal">call_method&lt;int&gt;(self, "f");</tt> dispatches the call back to Python.
</li><li><tt class="literal">def f(self): return 42</tt> is finally called.
</li></ol></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="boost_python.virtual_functions_with_default_implementations"></a>Virtual Functions with Default Implementations</h3></div></div><div></div></div><p>
Recall that in the <a href="class_virtual_functions.html" target="_top">
previous section</a>, we
wrapped a class with a pure virtual function that we then implemented in
C++ or Python classes derived from it. Our base class:</p><pre class="programlisting"><tt class="literal"><span class="keyword"> struct</span><span class="identifier"> Base</span><span class="special">
{</span><span class="keyword">
virtual</span><span class="keyword"> int</span><span class="identifier"> f</span><span class="special">()</span><span class="special"> =</span><span class="number"> 0</span><span class="special">;</span><span class="special">
};</span></tt></pre><p>
had a pure virtual function <tt class="literal">f</tt>. If, however, its member function <tt class="literal">f</tt> was
not declared as pure virtual:</p><pre class="programlisting"><tt class="literal"><span class="keyword"> struct</span><span class="identifier"> Base</span><span class="special">
{</span><span class="keyword">
virtual</span><span class="keyword"> int</span><span class="identifier"> f</span><span class="special">()</span><span class="special"> {</span><span class="keyword"> return</span><span class="number"> 0</span><span class="special">;</span><span class="special"> }</span><span class="special">
};</span></tt></pre><p>
and instead had a default implementation that returns <tt class="literal">0</tt>, as shown above,
we need to add a forwarding function that calls the <tt class="literal">Base</tt> default virtual
function <tt class="literal">f</tt> implementation:</p><pre class="programlisting"><tt class="literal"><span class="keyword"> struct</span><span class="identifier"> BaseWrap</span><span class="special"> :</span><span class="identifier"> Base</span><span class="special">
{</span><span class="identifier">
BaseWrap</span><span class="special">(</span><span class="identifier">PyObject</span><span class="special">*</span><span class="identifier"> self_</span><span class="special">)</span><span class="special">
:</span><span class="identifier"> self</span><span class="special">(</span><span class="identifier">self_</span><span class="special">)</span><span class="special"> {}</span><span class="keyword">
int</span><span class="identifier"> f</span><span class="special">()</span><span class="special"> {</span><span class="keyword"> return</span><span class="identifier"> call_method</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;(</span><span class="identifier">self</span><span class="special">,</span><span class="string"> "f"</span><span class="special">);</span><span class="special"> }</span><span class="keyword">
int</span><span class="identifier"> default_f</span><span class="special">()</span><span class="special"> {</span><span class="keyword"> return</span><span class="identifier"> Base</span><span class="special">::</span><span class="identifier">f</span><span class="special">();</span><span class="special"> }</span><span class="comment"> // &lt;&lt;=== ***ADDED***
</span><span class="identifier"> PyObject</span><span class="special">*</span><span class="identifier"> self</span><span class="special">;</span><span class="special">
};</span></tt></pre><p>
Then, Boost.Python needs to keep track of 1) the dispatch function <tt class="literal">f</tt> and
2) the forwarding function to its default implementation <tt class="literal">default_f</tt>.
There's a special <tt class="literal">def</tt> function for this purpose. Here's how it is
applied to our example above:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> class_</span><span class="special">&lt;</span><span class="identifier">Base</span><span class="special">,</span><span class="identifier"> BaseWrap</span><span class="special">,</span><span class="identifier"> BaseWrap</span><span class="special">,</span><span class="identifier"> boost</span><span class="special">::</span><span class="identifier">noncopyable</span><span class="special">&gt;(</span><span class="string">"Base"</span><span class="special">)</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">Base</span><span class="special">::</span><span class="identifier">f</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">BaseWrap</span><span class="special">::</span><span class="identifier">default_f</span><span class="special">)</span></tt></pre><p>
Note that we are allowing <tt class="literal">Base</tt> objects to be instantiated this time,
unlike before where we specifically defined the <tt class="literal">class_&lt;Base&gt;</tt> with
<tt class="literal">no_init</tt>.</p><p>
In Python, the results would be as expected:</p><pre class="programlisting"><tt class="literal"><span class="special"> &gt;&gt;&gt;</span><span class="identifier"> base</span><span class="special"> =</span><span class="identifier"> Base</span><span class="special">()</span><span class="special">
&gt;&gt;&gt;</span><span class="keyword"> class</span><span class="identifier"> Derived</span><span class="special">(</span><span class="identifier">Base</span><span class="special">):</span><span class="special">
...</span><span class="identifier"> def</span><span class="identifier"> f</span><span class="special">(</span><span class="identifier">self</span><span class="special">):</span><span class="special">
...</span><span class="keyword"> return</span><span class="number"> 42</span><span class="special">
...</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> derived</span><span class="special"> =</span><span class="identifier"> Derived</span><span class="special">()</span></tt></pre><p>
Calling <tt class="literal">base.f()</tt>:</p><pre class="programlisting"><tt class="literal"><span class="special"> &gt;&gt;&gt;</span><span class="identifier"> base</span><span class="special">.</span><span class="identifier">f</span><span class="special">()</span><span class="number">
0</span></tt></pre><p>
Calling <tt class="literal">derived.f()</tt>:</p><pre class="programlisting"><tt class="literal"><span class="special"> &gt;&gt;&gt;</span><span class="identifier"> derived</span><span class="special">.</span><span class="identifier">f</span><span class="special">()</span><span class="number">
42</span></tt></pre><p>
Calling <tt class="literal">call_f</tt>, passing in a <tt class="literal">base</tt> object:</p><pre class="programlisting"><tt class="literal"><span class="special"> &gt;&gt;&gt;</span><span class="identifier"> call_f</span><span class="special">(</span><span class="identifier">base</span><span class="special">)</span><span class="number">
0</span></tt></pre><p>
Calling <tt class="literal">call_f</tt>, passing in a <tt class="literal">derived</tt> object:</p><pre class="programlisting"><tt class="literal"><span class="special"> &gt;&gt;&gt;</span><span class="identifier"> call_f</span><span class="special">(</span><span class="identifier">derived</span><span class="special">)</span><span class="number">
42</span></tt></pre></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="boost_python.class_operators_special_functions"></a>Class Operators/Special Functions</h3></div></div><div></div></div><a name="class_operators_special_functions.python_operators"></a><h2><a name="id406432"></a>Python Operators</h2><p>
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.</p><p>
Consider a file position class <tt class="literal">FilePos</tt> and a set of operators that take
on FilePos instances:</p><pre class="programlisting"><tt class="literal"><span class="keyword"> class</span><span class="identifier"> FilePos</span><span class="special"> {</span><span class="comment"> /*...*/</span><span class="special"> };</span><span class="identifier">
FilePos</span><span class="keyword"> operator</span><span class="special">+(</span><span class="identifier">FilePos</span><span class="special">,</span><span class="keyword"> int</span><span class="special">);</span><span class="identifier">
FilePos</span><span class="keyword"> operator</span><span class="special">+(</span><span class="keyword">int</span><span class="special">,</span><span class="identifier"> FilePos</span><span class="special">);</span><span class="keyword">
int</span><span class="keyword"> operator</span><span class="special">-(</span><span class="identifier">FilePos</span><span class="special">,</span><span class="identifier"> FilePos</span><span class="special">);</span><span class="identifier">
FilePos</span><span class="keyword"> operator</span><span class="special">-(</span><span class="identifier">FilePos</span><span class="special">,</span><span class="keyword"> int</span><span class="special">);</span><span class="identifier">
FilePos</span><span class="special">&amp;</span><span class="keyword"> operator</span><span class="special">+=(</span><span class="identifier">FilePos</span><span class="special">&amp;,</span><span class="keyword"> int</span><span class="special">);</span><span class="identifier">
FilePos</span><span class="special">&amp;</span><span class="keyword"> operator</span><span class="special">-=(</span><span class="identifier">FilePos</span><span class="special">&amp;,</span><span class="keyword"> int</span><span class="special">);</span><span class="keyword">
bool</span><span class="keyword"> operator</span><span class="special">&lt;(</span><span class="identifier">FilePos</span><span class="special">,</span><span class="identifier"> FilePos</span><span class="special">);</span></tt></pre><p>
The class and the various operators can be mapped to Python rather easily
and intuitively:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> class_</span><span class="special">&lt;</span><span class="identifier">FilePos</span><span class="special">&gt;(</span><span class="string">"FilePos"</span><span class="special">)</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">self</span><span class="special"> +</span><span class="keyword"> int</span><span class="special">())</span><span class="comment"> // __add__
</span><span class="special"> .</span><span class="identifier">def</span><span class="special">(</span><span class="keyword">int</span><span class="special">()</span><span class="special"> +</span><span class="identifier"> self</span><span class="special">)</span><span class="comment"> // __radd__
</span><span class="special"> .</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">self</span><span class="special"> -</span><span class="identifier"> self</span><span class="special">)</span><span class="comment"> // __sub__
</span><span class="special"> .</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">self</span><span class="special"> -</span><span class="keyword"> int</span><span class="special">())</span><span class="comment"> // __sub__
</span><span class="special"> .</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">self</span><span class="special"> +=</span><span class="keyword"> int</span><span class="special">())</span><span class="comment"> // __iadd__
</span><span class="special"> .</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">self</span><span class="special"> -=</span><span class="identifier"> other</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;())</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">self</span><span class="special"> &lt;</span><span class="identifier"> self</span><span class="special">);</span><span class="comment"> // __lt__
</span></tt></pre><p>
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 <tt class="literal">self</tt> refers to FilePos object. Also, not every class <tt class="literal">T</tt> that
you might need to interact with in an operator expression is (cheaply)
default-constructible. You can use <tt class="literal">other&lt;T&gt;()</tt> in place of an actual
<tt class="literal">T</tt> instance when writing "self expressions".</p><a name="class_operators_special_functions.special_methods"></a><h2><a name="id407119"></a>Special Methods</h2><p>
Python has a few more <span class="emphasis"><em>Special Methods</em></span>. 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 <span class="emphasis"><em>special functions</em></span>. Example:</p><pre class="programlisting"><tt class="literal"><span class="keyword"> class</span><span class="identifier"> Rational</span><span class="special">
{</span><span class="keyword"> operator</span><span class="keyword"> double</span><span class="special">()</span><span class="keyword"> const</span><span class="special">;</span><span class="special"> };</span><span class="identifier">
Rational</span><span class="identifier"> pow</span><span class="special">(</span><span class="identifier">Rational</span><span class="special">,</span><span class="identifier"> Rational</span><span class="special">);</span><span class="identifier">
Rational</span><span class="identifier"> abs</span><span class="special">(</span><span class="identifier">Rational</span><span class="special">);</span><span class="identifier">
ostream</span><span class="special">&amp;</span><span class="keyword"> operator</span><span class="special">&lt;&lt;(</span><span class="identifier">ostream</span><span class="special">&amp;,</span><span class="identifier">Rational</span><span class="special">);</span><span class="identifier">
class_</span><span class="special">&lt;</span><span class="identifier">Rational</span><span class="special">&gt;()</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">float_</span><span class="special">(</span><span class="identifier">self</span><span class="special">))</span><span class="comment"> // __float__
</span><span class="special"> .</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">pow</span><span class="special">(</span><span class="identifier">self</span><span class="special">,</span><span class="identifier"> other</span><span class="special">&lt;</span><span class="identifier">Rational</span><span class="special">&gt;))</span><span class="comment"> // __pow__
</span><span class="special"> .</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">abs</span><span class="special">(</span><span class="identifier">self</span><span class="special">))</span><span class="comment"> // __abs__
</span><span class="special"> .</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">str</span><span class="special">(</span><span class="identifier">self</span><span class="special">))</span><span class="comment"> // __str__
</span><span class="special"> ;</span></tt></pre><p>
Need we say more?</p><div class="informaltable"><table class="table"><colgroup><col></colgroup><tbody><tr><td><span class="inlinemediaobject"><img src="images/lens.gif"></span> What is the business of <tt class="literal">operator&lt;&lt;</tt><tt class="literal">.def(str(self))</tt>?
Well, the method <tt class="literal">str</tt> requires the <tt class="literal">operator&lt;&lt;</tt> to do its work (i.e.
<tt class="literal">operator&lt;&lt;</tt> is used by the method defined by def(str(self)).</td></tr></tbody></table></div></div></div><table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr><td align="left"></td><td align="right"><small>Copyright © 2002-2004 Joel de Guzman, David Abrahams</small></td></tr></table><hr><div class="spirit-nav"><a accesskey="p" href="boost_python.hello.html"><img src="images/prev.png" alt="Prev"></a><a accesskey="u" href="index.html"><img src="images/up.png" alt="Up"></a><a accesskey="h" href="index.html"><img src="images/home.png" alt="Home"></a><a accesskey="n" href="boost_python.functions.html"><img src="images/next.png" alt="Next"></a></div></body></html>

View File

@@ -1,276 +0,0 @@
<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>Functions</title><link rel="stylesheet" href="boostbook.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="Chapter 1. Boost.Boost Python 1.0"><link rel="up" href="index.html" title="Chapter 1. Boost.Boost Python 1.0"><link rel="previous" href="boost_python.exposing.html" title=" Exposing Classes"><link rel="next" href="boost_python.object.html" title=" Object Interface"><link rel="chapter" href="index.html" title="Chapter 1. Boost.Boost Python 1.0"><link rel="subsection" href="boost_python.functions.html#boost_python.call_policies" title="Call Policies"><link rel="subsection" href="boost_python.functions.html#boost_python.overloading" title="Overloading"><link rel="subsection" href="boost_python.functions.html#boost_python.default_arguments" title="Default Arguments"><link rel="subsection" href="boost_python.functions.html#boost_python.auto_overloading" title="Auto-Overloading"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><table cellpadding="2" width="100%"><td valign="top"><img src="../../../../../../boost.png" alt="boost.png (6897 bytes)" width="277" height="86"></td><td align="center"><a href="../../index.htm">Home</a></td><td align="center"><a href="libraries.html">Libraries</a></td><td align="center"><a href="../../people/people.htm">People</a></td><td align="center"><a href="../../more/faq.htm">FAQ</a></td><td align="center"><a href="../../more/index.htm">More</a></td></table><hr><div class="spirit-nav"><a accesskey="p" href="boost_python.exposing.html"><img src="images/prev.png" alt="Prev"></a><a accesskey="u" href="index.html"><img src="images/up.png" alt="Up"></a><a accesskey="h" href="index.html"><img src="images/home.png" alt="Home"></a><a accesskey="n" href="boost_python.object.html"><img src="images/next.png" alt="Next"></a></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="boost_python.functions"></a>Functions</h2></div></div><div></div></div><div class="toc"><dl><dt><span class="section"><a href="boost_python.functions.html#boost_python.call_policies">Call Policies</a></span></dt><dt><span class="section"><a href="boost_python.functions.html#boost_python.overloading">Overloading</a></span></dt><dt><span class="section"><a href="boost_python.functions.html#boost_python.default_arguments">Default Arguments</a></span></dt><dt><span class="section"><a href="boost_python.functions.html#boost_python.auto_overloading">Auto-Overloading</a></span></dt></dl></div><p>
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.</p><div class="blockquote"><blockquote class="blockquote"><p><span class="emphasis"><em>Read on...</em></span></p></blockquote></div><p>
But before you do, you might want to fire up Python 2.2 or later and type
<tt class="literal">&gt;&gt;&gt; import this</tt>.</p><pre class="programlisting"><tt class="literal"> &gt;&gt;&gt; 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!
</tt></pre><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="boost_python.call_policies"></a>Call Policies</h3></div></div><div></div></div><p>
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:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> X</span><span class="special">&amp;</span><span class="identifier"> f</span><span class="special">(</span><span class="identifier">Y</span><span class="special">&amp;</span><span class="identifier"> y</span><span class="special">,</span><span class="identifier"> Z</span><span class="special">*</span><span class="identifier"> z</span><span class="special">);</span></tt></pre><p>
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</p><pre class="programlisting"><tt class="literal"><span class="special"> &gt;&gt;&gt;</span><span class="identifier"> x</span><span class="special"> =</span><span class="identifier"> f</span><span class="special">(</span><span class="identifier">y</span><span class="special">,</span><span class="identifier"> z</span><span class="special">)</span>#<span class="identifier"> x</span><span class="identifier"> refers</span><span class="identifier"> to</span><span class="identifier"> some</span><span class="identifier"> C</span><span class="special">++</span><span class="identifier"> X</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> del</span><span class="identifier"> y</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> x</span><span class="special">.</span><span class="identifier">some_method</span><span class="special">()</span>#<span class="identifier"> CRASH</span><span class="special">!</span></tt></pre><p>
What's the problem?</p><p>
Well, what if f() was implemented as shown below:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> X</span><span class="special">&amp;</span><span class="identifier"> f</span><span class="special">(</span><span class="identifier">Y</span><span class="special">&amp;</span><span class="identifier"> y</span><span class="special">,</span><span class="identifier"> Z</span><span class="special">*</span><span class="identifier"> z</span><span class="special">)</span><span class="special">
{</span><span class="identifier">
y</span><span class="special">.</span><span class="identifier">z</span><span class="special"> =</span><span class="identifier"> z</span><span class="special">;</span><span class="keyword">
return</span><span class="identifier"> y</span><span class="special">.</span><span class="identifier">x</span><span class="special">;</span><span class="special">
}</span></tt></pre><p>
The problem is that the lifetime of result X&amp; 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.</p><p>
Here's what's happening:</p><div class="orderedlist"><ol type="1"><li><tt class="literal">f</tt> is called passing in a reference to <tt class="literal">y</tt> and a pointer to <tt class="literal">z</tt></li><li>
A reference to <tt class="literal">y.x</tt> is returned
</li><li><tt class="literal">y</tt> is deleted. <tt class="literal">x</tt> is a dangling reference
</li><li><tt class="literal">x.some_method()</tt> is called
</li><li><span class="bold"><b>BOOM!</b></span></li></ol></div><p>
We could copy result into a new object:</p><pre class="programlisting"><tt class="literal"><span class="special"> &gt;&gt;&gt;</span><span class="identifier"> f</span><span class="special">(</span><span class="identifier">y</span><span class="special">,</span><span class="identifier"> z</span><span class="special">).</span><span class="identifier">set</span><span class="special">(</span><span class="number">42</span><span class="special">)</span>#<span class="identifier"> Result</span><span class="identifier"> disappears</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> y</span><span class="special">.</span><span class="identifier">x</span><span class="special">.</span><span class="identifier">get</span><span class="special">()</span>#<span class="identifier"> No</span><span class="identifier"> crash</span><span class="special">,</span><span class="identifier"> but</span><span class="identifier"> still</span><span class="identifier"> bad</span><span class="number">
3.14</span></tt></pre><p>
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.</p><p>
Our problems do not end there. Suppose Y is implemented as follows:</p><pre class="programlisting"><tt class="literal"><span class="keyword"> struct</span><span class="identifier"> Y</span><span class="special">
{</span><span class="identifier">
X</span><span class="identifier"> x</span><span class="special">;</span><span class="identifier"> Z</span><span class="special">*</span><span class="identifier"> z</span><span class="special">;</span><span class="keyword">
int</span><span class="identifier"> z_value</span><span class="special">()</span><span class="special"> {</span><span class="keyword"> return</span><span class="identifier"> z</span><span class="special">-&gt;</span><span class="identifier">value</span><span class="special">();</span><span class="special"> }</span><span class="special">
};</span></tt></pre><p>
Notice that the data member <tt class="literal">z</tt> is held by class Y using a raw
pointer. Now we have a potential dangling pointer problem inside Y:</p><pre class="programlisting"><tt class="literal"><span class="special"> &gt;&gt;&gt;</span><span class="identifier"> x</span><span class="special"> =</span><span class="identifier"> f</span><span class="special">(</span><span class="identifier">y</span><span class="special">,</span><span class="identifier"> z</span><span class="special">)</span>#<span class="identifier"> y</span><span class="identifier"> refers</span><span class="identifier"> to</span><span class="identifier"> z</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> del</span><span class="identifier"> z</span>#<span class="identifier"> Kill</span><span class="identifier"> the</span><span class="identifier"> z</span><span class="identifier"> object</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> y</span><span class="special">.</span><span class="identifier">z_value</span><span class="special">()</span>#<span class="identifier"> CRASH</span><span class="special">!</span></tt></pre><p>
For reference, here's the implementation of <tt class="literal">f</tt> again:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> X</span><span class="special">&amp;</span><span class="identifier"> f</span><span class="special">(</span><span class="identifier">Y</span><span class="special">&amp;</span><span class="identifier"> y</span><span class="special">,</span><span class="identifier"> Z</span><span class="special">*</span><span class="identifier"> z</span><span class="special">)</span><span class="special">
{</span><span class="identifier">
y</span><span class="special">.</span><span class="identifier">z</span><span class="special"> =</span><span class="identifier"> z</span><span class="special">;</span><span class="keyword">
return</span><span class="identifier"> y</span><span class="special">.</span><span class="identifier">x</span><span class="special">;</span><span class="special">
}</span></tt></pre><p>
Here's what's happening:</p><div class="orderedlist"><ol type="1"><li><tt class="literal">f</tt> is called passing in a reference to <tt class="literal">y</tt> and a pointer to <tt class="literal">z</tt></li><li>
A pointer to <tt class="literal">z</tt> is held by <tt class="literal">y</tt></li><li>
A reference to <tt class="literal">y.x</tt> is returned
</li><li><tt class="literal">z</tt> is deleted. <tt class="literal">y.z</tt> is a dangling pointer
</li><li><tt class="literal">y.z_value()</tt> is called
</li><li><tt class="literal">z-&gt;value()</tt> is called
</li><li><span class="bold"><b>BOOM!</b></span></li></ol></div><a name="call_policies.call_policies"></a><h2><a name="id408750"></a>Call Policies</h2><p>
Call Policies may be used in situations such as the example detailed above.
In our example, <tt class="literal">return_internal_reference</tt> and <tt class="literal">with_custodian_and_ward</tt>
are our friends:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span><span class="identifier"> f</span><span class="special">,</span><span class="identifier">
return_internal_reference</span><span class="special">&lt;</span><span class="number">1</span><span class="special">,</span><span class="identifier">
with_custodian_and_ward</span><span class="special">&lt;</span><span class="number">1</span><span class="special">,</span><span class="number"> 2</span><span class="special">&gt;</span><span class="special"> &gt;());</span></tt></pre><p>
What are the <tt class="literal">1</tt> and <tt class="literal">2</tt> parameters, you ask?</p><pre class="programlisting"><tt class="literal"><span class="identifier"> return_internal_reference</span><span class="special">&lt;</span><span class="number">1</span></tt></pre><p>
Informs Boost.Python that the first argument, in our case <tt class="literal">Y&amp; y</tt>, is the
owner of the returned reference: <tt class="literal">X&amp;</tt>. The "<tt class="literal">1</tt>" simply specifies the
first argument. In short: "return an internal reference <tt class="literal">X&amp;</tt> owned by the
1st argument <tt class="literal">Y&amp; y</tt>".</p><pre class="programlisting"><tt class="literal"><span class="identifier"> with_custodian_and_ward</span><span class="special">&lt;</span><span class="number">1</span><span class="special">,</span><span class="number"> 2</span><span class="special">&gt;</span></tt></pre><p>
Informs Boost.Python that the lifetime of the argument indicated by ward
(i.e. the 2nd argument: <tt class="literal">Z* z</tt>) is dependent on the lifetime of the
argument indicated by custodian (i.e. the 1st argument: <tt class="literal">Y&amp; y</tt>).</p><p>
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:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> policy1</span><span class="special">&lt;</span><span class="identifier">args</span><span class="special">...,</span><span class="identifier">
policy2</span><span class="special">&lt;</span><span class="identifier">args</span><span class="special">...,</span><span class="identifier">
policy3</span><span class="special">&lt;</span><span class="identifier">args</span><span class="special">...&gt;</span><span class="special"> &gt;</span><span class="special"> &gt;</span></tt></pre><p>
Here is the list of predefined call policies. A complete reference detailing
these can be found <a href="../../v2/reference.html#models_of_call_policies" target="_top">
here</a>.</p><div class="itemizedlist"><ul type="disc"><li><span class="bold"><b>with_custodian_and_ward</b></span><p></p>
Ties lifetimes of the arguments
</li><li><span class="bold"><b>with_custodian_and_ward_postcall</b></span><p></p>
Ties lifetimes of the arguments and results
</li><li><span class="bold"><b>return_internal_reference</b></span><p></p>
Ties lifetime of one argument to that of result
</li><li><span class="bold"><b>return_value_policy&lt;T&gt; with T one of:</b></span><p></p></li><li><span class="bold"><b>reference_existing_object</b></span><p></p>
naive (dangerous) approach
</li><li><span class="bold"><b>copy_const_reference</b></span><p></p>
Boost.Python v1 approach
</li><li><span class="bold"><b>copy_non_const_reference</b></span><p></p></li><li><span class="bold"><b>manage_new_object</b></span><p></p>
Adopt a pointer and hold the instance
</li></ul></div><div class="informaltable"><table class="table"><colgroup><col></colgroup><tbody><tr><td><span class="inlinemediaobject"><img src="images/smiley.gif"></span><span class="bold"><b>Remember the Zen, Luke:</b></span><p></p><p></p>
"Explicit is better than implicit"<p></p>
"In the face of ambiguity, refuse the temptation to guess"<p></p></td></tr></tbody></table></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="boost_python.overloading"></a>Overloading</h3></div></div><div></div></div><p>
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.</p><p>
We have here our C++ class:</p><pre class="programlisting"><tt class="literal"><span class="keyword"> struct</span><span class="identifier"> X</span><span class="special">
{</span><span class="keyword">
bool</span><span class="identifier"> f</span><span class="special">(</span><span class="keyword">int</span><span class="identifier"> a</span><span class="special">)</span><span class="special">
{</span><span class="keyword">
return</span><span class="keyword"> true</span><span class="special">;</span><span class="special">
}</span><span class="keyword">
bool</span><span class="identifier"> f</span><span class="special">(</span><span class="keyword">int</span><span class="identifier"> a</span><span class="special">,</span><span class="keyword"> double</span><span class="identifier"> b</span><span class="special">)</span><span class="special">
{</span><span class="keyword">
return</span><span class="keyword"> true</span><span class="special">;</span><span class="special">
}</span><span class="keyword">
bool</span><span class="identifier"> f</span><span class="special">(</span><span class="keyword">int</span><span class="identifier"> a</span><span class="special">,</span><span class="keyword"> double</span><span class="identifier"> b</span><span class="special">,</span><span class="keyword"> char</span><span class="identifier"> c</span><span class="special">)</span><span class="special">
{</span><span class="keyword">
return</span><span class="keyword"> true</span><span class="special">;</span><span class="special">
}</span><span class="keyword">
int</span><span class="identifier"> f</span><span class="special">(</span><span class="keyword">int</span><span class="identifier"> a</span><span class="special">,</span><span class="keyword"> int</span><span class="identifier"> b</span><span class="special">,</span><span class="keyword"> int</span><span class="identifier"> c</span><span class="special">)</span><span class="special">
{</span><span class="keyword">
return</span><span class="identifier"> a</span><span class="special"> +</span><span class="identifier"> b</span><span class="special"> +</span><span class="identifier"> c</span><span class="special">;</span><span class="special">
};</span><span class="special">
};</span></tt></pre><p>
Class X has 4 overloaded functions. We shall start by introducing some
member function pointer variables:</p><pre class="programlisting"><tt class="literal"><span class="keyword"> bool</span><span class="special"> (</span><span class="identifier">X</span><span class="special">::*</span><span class="identifier">fx1</span><span class="special">)(</span><span class="keyword">int</span><span class="special">)</span><span class="special"> =</span><span class="special"> &amp;</span><span class="identifier">X</span><span class="special">::</span><span class="identifier">f</span><span class="special">;</span><span class="keyword">
bool</span><span class="special"> (</span><span class="identifier">X</span><span class="special">::*</span><span class="identifier">fx2</span><span class="special">)(</span><span class="keyword">int</span><span class="special">,</span><span class="keyword"> double</span><span class="special">)</span><span class="special"> =</span><span class="special"> &amp;</span><span class="identifier">X</span><span class="special">::</span><span class="identifier">f</span><span class="special">;</span><span class="keyword">
bool</span><span class="special"> (</span><span class="identifier">X</span><span class="special">::*</span><span class="identifier">fx3</span><span class="special">)(</span><span class="keyword">int</span><span class="special">,</span><span class="keyword"> double</span><span class="special">,</span><span class="keyword"> char</span><span class="special">)=</span><span class="special"> &amp;</span><span class="identifier">X</span><span class="special">::</span><span class="identifier">f</span><span class="special">;</span><span class="keyword">
int</span><span class="special"> (</span><span class="identifier">X</span><span class="special">::*</span><span class="identifier">fx4</span><span class="special">)(</span><span class="keyword">int</span><span class="special">,</span><span class="keyword"> int</span><span class="special">,</span><span class="keyword"> int</span><span class="special">)</span><span class="special"> =</span><span class="special"> &amp;</span><span class="identifier">X</span><span class="special">::</span><span class="identifier">f</span><span class="special">;</span></tt></pre><p>
With these in hand, we can proceed to define and wrap this for Python:</p><pre class="programlisting"><tt class="literal"><span class="special"> .</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span><span class="identifier"> fx1</span><span class="special">)</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span><span class="identifier"> fx2</span><span class="special">)</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span><span class="identifier"> fx3</span><span class="special">)</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span><span class="identifier"> fx4</span><span class="special">)</span></tt></pre></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="boost_python.default_arguments"></a>Default Arguments</h3></div></div><div></div></div><p>
Boost.Python wraps (member) function pointers. Unfortunately, C++ function
pointers carry no default argument info. Take a function <tt class="literal">f</tt> with default
arguments:</p><pre class="programlisting"><tt class="literal"><span class="keyword"> int</span><span class="identifier"> f</span><span class="special">(</span><span class="keyword">int</span><span class="special">,</span><span class="keyword"> double</span><span class="special"> =</span><span class="number"> 3.14</span><span class="special">,</span><span class="keyword"> char</span><span class="keyword"> const</span><span class="special">*</span><span class="special"> =</span><span class="string"> "hello"</span><span class="special">);</span></tt></pre><p>
But the type of a pointer to the function <tt class="literal">f</tt> has no information
about its default arguments:</p><pre class="programlisting"><tt class="literal"><span class="keyword"> int</span><span class="special">(*</span><span class="identifier">g</span><span class="special">)(</span><span class="keyword">int</span><span class="special">,</span><span class="keyword">double</span><span class="special">,</span><span class="keyword">char</span><span class="keyword"> const</span><span class="special">*)</span><span class="special"> =</span><span class="identifier"> f</span><span class="special">;</span><span class="comment"> // defaults lost!
</span></tt></pre><p>
When we pass this function pointer to the <tt class="literal">def</tt> function, there is no way
to retrieve the default arguments:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span><span class="identifier"> f</span><span class="special">);</span><span class="comment"> // defaults lost!
</span></tt></pre><p>
Because of this, when wrapping C++ code, we had to resort to manual
wrapping as outlined in the <a href="overloading.html" target="_top">
previous section</a>, or
writing thin wrappers:</p><pre class="programlisting"><tt class="literal"><span class="comment"> // write "thin wrappers"
</span><span class="keyword"> int</span><span class="identifier"> f1</span><span class="special">(</span><span class="keyword">int</span><span class="identifier"> x</span><span class="special">)</span><span class="special"> {</span><span class="identifier"> f</span><span class="special">(</span><span class="identifier">x</span><span class="special">);</span><span class="special"> }</span><span class="keyword">
int</span><span class="identifier"> f2</span><span class="special">(</span><span class="keyword">int</span><span class="identifier"> x</span><span class="special">,</span><span class="keyword"> double</span><span class="identifier"> y</span><span class="special">)</span><span class="special"> {</span><span class="identifier"> f</span><span class="special">(</span><span class="identifier">x</span><span class="special">,</span><span class="identifier">y</span><span class="special">);</span><span class="special"> }</span><span class="comment">
/*...*/
// in module init
</span><span class="identifier"> def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span><span class="identifier"> f</span><span class="special">);</span><span class="comment"> // all arguments
</span><span class="identifier"> def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span><span class="identifier"> f2</span><span class="special">);</span><span class="comment"> // two arguments
</span><span class="identifier"> def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span><span class="identifier"> f1</span><span class="special">);</span><span class="comment"> // one argument
</span></tt></pre><p>
When you want to wrap functions (or member functions) that either:</p><div class="itemizedlist"><ul type="disc"><li>
have default arguments, or
</li><li>
are overloaded with a common sequence of initial arguments
</li></ul></div><a name="default_arguments.boost_python_function_overloads"></a><h2><a name="id410570"></a>BOOST_PYTHON_FUNCTION_OVERLOADS</h2><p>
Boost.Python now has a way to make it easier. For instance, given a function:</p><pre class="programlisting"><tt class="literal"><span class="keyword"> int</span><span class="identifier"> foo</span><span class="special">(</span><span class="keyword">int</span><span class="identifier"> a</span><span class="special">,</span><span class="keyword"> char</span><span class="identifier"> b</span><span class="special"> =</span><span class="number"> 1</span><span class="special">,</span><span class="keyword"> unsigned</span><span class="identifier"> c</span><span class="special"> =</span><span class="number"> 2</span><span class="special">,</span><span class="keyword"> double</span><span class="identifier"> d</span><span class="special"> =</span><span class="number"> 3</span><span class="special">)</span><span class="special">
{</span><span class="comment">
/*...*/</span><span class="special">
}</span></tt></pre><p>
The macro invocation:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> BOOST_PYTHON_FUNCTION_OVERLOADS</span><span class="special">(</span><span class="identifier">foo_overloads</span><span class="special">,</span><span class="identifier"> foo</span><span class="special">,</span><span class="number"> 1</span><span class="special">,</span><span class="number"> 4</span><span class="special">)</span></tt></pre><p>
will automatically create the thin wrappers for us. This macro will create
a class <tt class="literal">foo_overloads</tt> that can be passed on to <tt class="literal">def(...)</tt>. The third
and fourth macro argument are the minimum arguments and maximum arguments,
respectively. In our <tt class="literal">foo</tt> function the minimum number of arguments is 1
and the maximum number of arguments is 4. The <tt class="literal">def(...)</tt> function will
automatically add all the foo variants for us:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> def</span><span class="special">(</span><span class="string">"foo"</span><span class="special">,</span><span class="identifier"> foo</span><span class="special">,</span><span class="identifier"> foo_overloads</span><span class="special">());</span></tt></pre><a name="default_arguments.boost_python_member_function_overloads"></a><h2><a name="id410852"></a>BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</h2><p>
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.</p><p>
Like <tt class="literal">BOOST_PYTHON_FUNCTION_OVERLOADS</tt>,
<tt class="literal">BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</tt> may be used to automatically create
the thin wrappers for wrapping member functions. Let's have an example:</p><pre class="programlisting"><tt class="literal"><span class="keyword"> struct</span><span class="identifier"> george</span><span class="special">
{</span><span class="keyword">
void</span><span class="identifier">
wack_em</span><span class="special">(</span><span class="keyword">int</span><span class="identifier"> a</span><span class="special">,</span><span class="keyword"> int</span><span class="identifier"> b</span><span class="special"> =</span><span class="number"> 0</span><span class="special">,</span><span class="keyword"> char</span><span class="identifier"> c</span><span class="special"> =</span><span class="char"> 'x'</span><span class="special">)</span><span class="special">
{</span><span class="comment">
/*...*/</span><span class="special">
}</span><span class="special">
};</span></tt></pre><p>
The macro invocation:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</span><span class="special">(</span><span class="identifier">george_overloads</span><span class="special">,</span><span class="identifier"> wack_em</span><span class="special">,</span><span class="number"> 1</span><span class="special">,</span><span class="number"> 3</span><span class="special">)</span></tt></pre><p>
will generate a set of thin wrappers for george's <tt class="literal">wack_em</tt> 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
<tt class="literal">george_overloads</tt> that can then be used as an argument to <tt class="literal">def(...)</tt>:</p><pre class="programlisting"><tt class="literal"><span class="special"> .</span><span class="identifier">def</span><span class="special">(</span><span class="string">"wack_em"</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">george</span><span class="special">::</span><span class="identifier">wack_em</span><span class="special">,</span><span class="identifier"> george_overloads</span><span class="special">());</span></tt></pre><p>
See the <a href="../../v2/overloads.html#BOOST_PYTHON_FUNCTION_OVERLOADS-spec" target="_top">
overloads reference</a>
for details.</p><a name="default_arguments.init_and_optional"></a><h2><a name="id411180"></a>init and optional</h2><p>
A similar facility is provided for class constructors, again, with
default arguments or a sequence of overloads. Remember <tt class="literal">init&lt;...&gt;</tt>? For example,
given a class X with a constructor:</p><pre class="programlisting"><tt class="literal"><span class="keyword"> struct</span><span class="identifier"> X</span><span class="special">
{</span><span class="identifier">
X</span><span class="special">(</span><span class="keyword">int</span><span class="identifier"> a</span><span class="special">,</span><span class="keyword"> char</span><span class="identifier"> b</span><span class="special"> =</span><span class="char"> 'D'</span><span class="special">,</span><span class="identifier"> std</span><span class="special">::</span><span class="identifier">string</span><span class="identifier"> c</span><span class="special"> =</span><span class="string"> "constructor"</span><span class="special">,</span><span class="keyword"> double</span><span class="identifier"> d</span><span class="special"> =</span><span class="number"> 0.0</span><span class="special">);</span><span class="comment">
/*...*/</span><span class="special">
}</span></tt></pre><p>
You can easily add this constructor to Boost.Python in one shot:</p><pre class="programlisting"><tt class="literal"><span class="special"> .</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">init</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">,</span><span class="identifier"> optional</span><span class="special">&lt;</span><span class="keyword">char</span><span class="special">,</span><span class="identifier"> std</span><span class="special">::</span><span class="identifier">string</span><span class="special">,</span><span class="keyword"> double</span><span class="special">&gt;</span><span class="special"> &gt;())</span></tt></pre><p>
Notice the use of <tt class="literal">init&lt;...&gt;</tt> and <tt class="literal">optional&lt;...&gt;</tt> to signify the default
(optional arguments).</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="boost_python.auto_overloading"></a>Auto-Overloading</h3></div></div><div></div></div><p>
It was mentioned in passing in the previous section that
<tt class="literal">BOOST_PYTHON_FUNCTION_OVERLOADS</tt> and <tt class="literal">BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</tt>
can also be used for overloaded functions and member functions with a
common sequence of initial arguments. Here is an example:</p><pre class="programlisting"><tt class="literal"><span class="keyword"> void</span><span class="identifier"> foo</span><span class="special">()</span><span class="special">
{</span><span class="comment">
/*...*/</span><span class="special">
}</span><span class="keyword">
void</span><span class="identifier"> foo</span><span class="special">(</span><span class="keyword">bool</span><span class="identifier"> a</span><span class="special">)</span><span class="special">
{</span><span class="comment">
/*...*/</span><span class="special">
}</span><span class="keyword">
void</span><span class="identifier"> foo</span><span class="special">(</span><span class="keyword">bool</span><span class="identifier"> a</span><span class="special">,</span><span class="keyword"> int</span><span class="identifier"> b</span><span class="special">)</span><span class="special">
{</span><span class="comment">
/*...*/</span><span class="special">
}</span><span class="keyword">
void</span><span class="identifier"> foo</span><span class="special">(</span><span class="keyword">bool</span><span class="identifier"> a</span><span class="special">,</span><span class="keyword"> int</span><span class="identifier"> b</span><span class="special">,</span><span class="keyword"> char</span><span class="identifier"> c</span><span class="special">)</span><span class="special">
{</span><span class="comment">
/*...*/</span><span class="special">
}</span></tt></pre><p>
Like in the previous section, we can generate thin wrappers for these
overloaded functions in one-shot:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> BOOST_PYTHON_FUNCTION_OVERLOADS</span><span class="special">(</span><span class="identifier">foo_overloads</span><span class="special">,</span><span class="identifier"> foo</span><span class="special">,</span><span class="number"> 0</span><span class="special">,</span><span class="number"> 3</span><span class="special">)</span></tt></pre><p>
Then...</p><pre class="programlisting"><tt class="literal"><span class="special"> .</span><span class="identifier">def</span><span class="special">(</span><span class="string">"foo"</span><span class="special">,</span><span class="identifier"> foo</span><span class="special">,</span><span class="identifier"> foo_overloads</span><span class="special">());</span></tt></pre><p>
Notice though that we have a situation now where we have a minimum of zero
(0) arguments and a maximum of 3 arguments.</p><a name="auto_overloading.manual_wrapping"></a><h2><a name="id411831"></a>Manual Wrapping</h2><p>
It is important to emphasize however that <span class="bold"><b>the overloaded functions must
have a common sequence of initial arguments</b></span>. Otherwise, our scheme above
will not work. If this is not the case, we have to wrap our functions
<a href="overloading.html" target="_top">
manually</a>.</p><p>
Actually, we can mix and match manual wrapping of overloaded functions and
automatic wrapping through <tt class="literal">BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</tt> and
its sister, <tt class="literal">BOOST_PYTHON_FUNCTION_OVERLOADS</tt>. Following up on our example
presented in the section <a href="overloading.html" target="_top">
on overloading</a>, since the
first 4 overload functins have a common sequence of initial arguments, we
can use <tt class="literal">BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</tt> to automatically wrap the
first three of the <tt class="literal">def</tt>s and manually wrap just the last. Here's
how we'll do this:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</span><span class="special">(</span><span class="identifier">xf_overloads</span><span class="special">,</span><span class="identifier"> f</span><span class="special">,</span><span class="number"> 1</span><span class="special">,</span><span class="number"> 4</span><span class="special">)</span></tt></pre><p>
Create a member function pointers as above for both X::f overloads:</p><pre class="programlisting"><tt class="literal"><span class="keyword"> bool</span><span class="special"> (</span><span class="identifier">X</span><span class="special">::*</span><span class="identifier">fx1</span><span class="special">)(</span><span class="keyword">int</span><span class="special">,</span><span class="keyword"> double</span><span class="special">,</span><span class="keyword"> char</span><span class="special">)</span><span class="special"> =</span><span class="special"> &amp;</span><span class="identifier">X</span><span class="special">::</span><span class="identifier">f</span><span class="special">;</span><span class="keyword">
int</span><span class="special"> (</span><span class="identifier">X</span><span class="special">::*</span><span class="identifier">fx2</span><span class="special">)(</span><span class="keyword">int</span><span class="special">,</span><span class="keyword"> int</span><span class="special">,</span><span class="keyword"> int</span><span class="special">)</span><span class="special"> =</span><span class="special"> &amp;</span><span class="identifier">X</span><span class="special">::</span><span class="identifier">f</span><span class="special">;</span></tt></pre><p>
Then...</p><pre class="programlisting"><tt class="literal"><span class="special"> .</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span><span class="identifier"> fx1</span><span class="special">,</span><span class="identifier"> xf_overloads</span><span class="special">());</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span><span class="identifier"> fx2</span><span class="special">)</span></tt></pre></div></div><table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr><td align="left"></td><td align="right"><small>Copyright © 2002-2004 Joel de Guzman, David Abrahams</small></td></tr></table><hr><div class="spirit-nav"><a accesskey="p" href="boost_python.exposing.html"><img src="images/prev.png" alt="Prev"></a><a accesskey="u" href="index.html"><img src="images/up.png" alt="Up"></a><a accesskey="h" href="index.html"><img src="images/home.png" alt="Home"></a><a accesskey="n" href="boost_python.object.html"><img src="images/next.png" alt="Next"></a></div></body></html>

View File

@@ -1,130 +0,0 @@
<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title> Building Hello World</title><link rel="stylesheet" href="boostbook.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="Chapter 1. Boost.Boost Python 1.0"><link rel="up" href="index.html" title="Chapter 1. Boost.Boost Python 1.0"><link rel="previous" href="index.html" title="Chapter 1. Boost.Boost Python 1.0"><link rel="next" href="boost_python.exposing.html" title=" Exposing Classes"><link rel="chapter" href="index.html" title="Chapter 1. Boost.Boost Python 1.0"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><table cellpadding="2" width="100%"><td valign="top"><img src="../../../../../../boost.png" alt="boost.png (6897 bytes)" width="277" height="86"></td><td align="center"><a href="../../index.htm">Home</a></td><td align="center"><a href="libraries.html">Libraries</a></td><td align="center"><a href="../../people/people.htm">People</a></td><td align="center"><a href="../../more/faq.htm">FAQ</a></td><td align="center"><a href="../../more/index.htm">More</a></td></table><hr><div class="spirit-nav"><a accesskey="p" href="index.html"><img src="images/prev.png" alt="Prev"></a><a accesskey="u" href="index.html"><img src="images/up.png" alt="Up"></a><a accesskey="h" href="index.html"><img src="images/home.png" alt="Home"></a><a accesskey="n" href="boost_python.exposing.html"><img src="images/next.png" alt="Next"></a></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="boost_python.hello"></a> Building Hello World</h2></div></div><div></div></div><a name="hello.from_start_to_finish"></a><h2><a name="id387283"></a>From Start To Finish</h2><p>
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: <span class="bold"><b>bjam</b></span>.</p><div class="informaltable"><table class="table"><colgroup><col></colgroup><tbody><tr><td><span class="inlinemediaobject"><img src="images/lens.gif"></span><span class="bold"><b>Building without bjam</b></span><p></p><p></p></td></tr></tbody></table></div><p>
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 <tt class="literal">bjam</tt>.</p><p>
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.
]</p><p>
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: <a href="../../building.html" target="_top">
building.html</a>.
After this brief <span class="emphasis"><em>bjam</em></span> tutorial, we should have built two DLLs:</p><div class="itemizedlist"><ul type="disc"><li>
boost_python.dll
</li><li>
hello.pyd
</li></ul></div><p>
if you are on Windows, and</p><div class="itemizedlist"><ul type="disc"><li>
libboost_python.so
</li><li>
hello.so
</li></ul></div><p>
if you are on Unix.</p><p>
The tutorial example can be found in the directory:
<tt class="literal">libs/python/example/tutorial</tt>. There, you can find:</p><div class="itemizedlist"><ul type="disc"><li>
hello.cpp
</li><li>
Jamfile
</li></ul></div><p>
The <tt class="literal">hello.cpp</tt> file is our C++ hello world example. The <tt class="literal">Jamfile</tt> is a
minimalist <span class="emphasis"><em>bjam</em></span> script that builds the DLLs for us.</p><p>
Before anything else, you should have the bjam executable in your boost
directory or somewhere in your path such that <tt class="literal">bjam</tt> 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 <a href="http://boost.sourceforge.net/jam-executables/bin.ntx86/bjam.zip" target="_top">
here</a>.
The complete list of bjam pre-built
executables can be found <a href="../../../../../tools/build/index.html#Jam" target="_top">
here</a>.</p><a name="hello.let_s_jam_"></a><h2><a name="id401473"></a>Let's Jam!</h2><p><span class="inlinemediaobject"><img src="images/jam.png"></span></p><p>
Here is our minimalist Jamfile:</p><pre class="programlisting"><tt class="literal"> subproject libs/python/example/tutorial ;</tt></pre><p>
[pre
subproject libs/python/example/tutorial ;</p><pre class="programlisting"><tt class="literal"><span class="identifier"> SEARCH</span><span class="identifier"> on</span><span class="identifier"> python</span><span class="special">.</span><span class="identifier">jam</span><span class="special"> =</span>#<span class="special">(</span><span class="identifier">BOOST_BUILD_PATH</span><span class="special">)</span><span class="special"> ;</span><span class="identifier">
include</span><span class="identifier"> python</span><span class="special">.</span><span class="identifier">jam</span><span class="special"> ;</span><span class="identifier">
extension</span><span class="identifier"> hello</span>#<span class="identifier"> Declare</span><span class="identifier"> a</span><span class="identifier"> Python</span><span class="identifier"> extension</span><span class="identifier"> called</span><span class="identifier"> hello</span><span class="special">
:</span><span class="identifier"> hello</span><span class="special">.</span><span class="identifier">cpp</span>#<span class="identifier"> source</span><span class="special">
&lt;</span><span class="identifier">dll</span><span class="special">&gt;../../</span><span class="identifier">build</span><span class="special">/</span><span class="identifier">boost_python</span>#<span class="identifier"> dependencies</span><span class="special">
;</span></tt></pre><p>
SEARCH on python.jam = $(BOOST_BUILD_PATH) ;
include python.jam ;</p><pre class="programlisting"><tt class="literal"><span class="identifier"> extension</span><span class="identifier"> hello</span>#<span class="identifier"> Declare</span><span class="identifier"> a</span><span class="identifier"> Python</span><span class="identifier"> extension</span><span class="identifier"> called</span><span class="identifier"> hello</span><span class="special">
:</span><span class="identifier"> hello</span><span class="special">.</span><span class="identifier">cpp</span>#<span class="identifier"> source</span><span class="special">
&lt;</span><span class="identifier">dll</span><span class="special">&gt;../../</span><span class="identifier">build</span><span class="special">/</span><span class="identifier">boost_python</span>#<span class="identifier"> dependencies</span><span class="special">
;</span></tt></pre><p>
extension hello # Declare a Python extension called hello
: hello.cpp # source
&lt;dll&gt;../../build/boost_python # dependencies
;
]</p><p>
First, we need to specify our location in the boost project hierarchy.
It so happens that the tutorial example is located in <tt class="literal">/libs/python/example/tutorial</tt>.
Thus:</p><pre class="programlisting"><tt class="literal"> subproject libs/python/example/tutorial ;
</tt></pre><p>
Then we will include the definitions needed by Python modules:</p><pre class="programlisting"><tt class="literal"> SEARCH on python.jam = $(BOOST_BUILD_PATH) ;
include python.jam ;
</tt></pre><p>
Finally we declare our <tt class="literal">hello</tt> extension:</p><pre class="programlisting"><tt class="literal"> extension hello # Declare a Python extension called hello
: hello.cpp # source
&lt;dll&gt;../../build/boost_python # dependencies
;
</tt></pre><a name="hello.running_bjam"></a><h2><a name="id401888"></a>Running bjam</h2><p><span class="emphasis"><em>bjam</em></span> is run using your operating system's command line interpreter.</p><div class="blockquote"><blockquote class="blockquote"><p>Start it up.</p></blockquote></div><p>
Make sure that the environment is set so that we can invoke the C++
compiler. With MSVC, that would mean running the <tt class="literal">Vcvars32.bat</tt> batch
file. For instance:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> C</span><span class="special">:\</span><span class="identifier">Program</span><span class="identifier"> Files</span><span class="special">\</span><span class="identifier">Microsoft</span><span class="identifier"> Visual</span><span class="identifier"> Studio</span><span class="special">\</span><span class="identifier">VC98</span><span class="special">\</span><span class="identifier">bin</span><span class="special">\</span><span class="identifier">Vcvars32</span><span class="special">.</span><span class="identifier">bat</span></tt></pre><p>
Some environment variables will have to be setup for proper building of our
Python modules. Example:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> set</span><span class="identifier"> PYTHON_ROOT</span><span class="special">=</span><span class="identifier">c</span><span class="special">:/</span><span class="identifier">dev</span><span class="special">/</span><span class="identifier">tools</span><span class="special">/</span><span class="identifier">python</span><span class="identifier">
set</span><span class="identifier"> PYTHON_VERSION</span><span class="special">=</span><span class="number">2.2</span></tt></pre><p>
The above assumes that the Python installation is in <tt class="literal">c:/dev/tools/python</tt>
and that we are using Python version 2.2. You'll have to tweak this path
appropriately. <span class="inlinemediaobject"><img src="images/note.gif"></span> Be sure not to include a third number, e.g. <span class="bold"><b>not</b></span> "2.2.1",
even if that's the version you have.</p><p>
Now we are ready... Be sure to <tt class="literal">cd</tt> to <tt class="literal">libs/python/example/tutorial</tt>
where the tutorial <tt class="literal">"hello.cpp"</tt> and the <tt class="literal">"Jamfile"</tt> is situated.</p><p>
Finally:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> bjam</span><span class="special"> -</span><span class="identifier">sTOOLS</span><span class="special">=</span><span class="identifier">msvc</span></tt></pre><p>
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
<a href="../../../../../tools/build/index.html" target="_top">
Building Boost Libraries</a> for
further details.</p><p>
It should be building now:</p><pre class="programlisting"><tt class="literal"> cd C:\dev\boost\libs\python\example\tutorial
bjam -sTOOLS=msvc
...patience...
...found 1703 targets...
...updating 40 targets...
</tt></pre><p>
And so on... Finally:</p><pre class="programlisting"><tt class="literal"> 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...
</tt></pre><p>
If all is well, you should now have:</p><div class="itemizedlist"><ul type="disc"><li>
boost_python.dll
</li><li>
hello.pyd
</li></ul></div><p>
if you are on Windows, and</p><div class="itemizedlist"><ul type="disc"><li>
libboost_python.so
</li><li>
hello.so
</li></ul></div><p>
if you are on Unix.</p><p><tt class="literal">boost_python.dll</tt> can be found somewhere in <tt class="literal">libs\python\build\bin</tt>
while <tt class="literal">hello.pyd</tt> can be found somewhere in
<tt class="literal">libs\python\example\tutorial\bin</tt>. 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.</p><p>
You may now fire up Python and run our hello module:</p><pre class="programlisting"><tt class="literal"><span class="special"> &gt;&gt;&gt;</span><span class="identifier"> import</span><span class="identifier"> hello</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> print</span><span class="identifier"> hello</span><span class="special">.</span><span class="identifier">greet</span><span class="special">()</span><span class="identifier">
hello</span><span class="special">,</span><span class="identifier"> world</span></tt></pre><div class="blockquote"><blockquote class="blockquote"><p><span class="bold"><b>There you go... Have fun!</b></span></p></blockquote></div></div><table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr><td align="left"></td><td align="right"><small>Copyright © 2002-2004 Joel de Guzman, David Abrahams</small></td></tr></table><hr><div class="spirit-nav"><a accesskey="p" href="index.html"><img src="images/prev.png" alt="Prev"></a><a accesskey="u" href="index.html"><img src="images/up.png" alt="Up"></a><a accesskey="h" href="index.html"><img src="images/home.png" alt="Home"></a><a accesskey="n" href="boost_python.exposing.html"><img src="images/next.png" alt="Next"></a></div></body></html>

View File

@@ -1,53 +0,0 @@
<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>Iterators</title><link rel="stylesheet" href="boostbook.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="Chapter 1. Boost.Boost Python 1.0"><link rel="up" href="index.html" title="Chapter 1. Boost.Boost Python 1.0"><link rel="previous" href="boost_python.embedding.html" title="Embedding"><link rel="next" href="boost_python.exception.html" title=" Exception Translation"><link rel="chapter" href="index.html" title="Chapter 1. Boost.Boost Python 1.0"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><table cellpadding="2" width="100%"><td valign="top"><img src="../../../../../../boost.png" alt="boost.png (6897 bytes)" width="277" height="86"></td><td align="center"><a href="../../index.htm">Home</a></td><td align="center"><a href="libraries.html">Libraries</a></td><td align="center"><a href="../../people/people.htm">People</a></td><td align="center"><a href="../../more/faq.htm">FAQ</a></td><td align="center"><a href="../../more/index.htm">More</a></td></table><hr><div class="spirit-nav"><a accesskey="p" href="boost_python.embedding.html"><img src="images/prev.png" alt="Prev"></a><a accesskey="u" href="index.html"><img src="images/up.png" alt="Up"></a><a accesskey="h" href="index.html"><img src="images/home.png" alt="Home"></a><a accesskey="n" href="boost_python.exception.html"><img src="images/next.png" alt="Next"></a></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="boost_python.iterators"></a>Iterators</h2></div></div><div></div></div><p>
In C++, and STL in particular, we see iterators everywhere. Python also has
iterators, but these are two very different beasts.</p><p><span class="bold"><b>C++ iterators:</b></span></p><div class="itemizedlist"><ul type="disc"><li>
C++ has 5 type categories (random-access, bidirectional, forward, input, output)
</li><li>
There are 2 Operation categories: reposition, access
</li><li>
A pair of iterators is needed to represent a (first/last) range.
</li></ul></div><p><span class="bold"><b>Python Iterators:</b></span></p><div class="itemizedlist"><ul type="disc"><li>
1 category (forward)
</li><li>
1 operation category (next())
</li><li>
Raises StopIteration exception at end
</li></ul></div><p>
The typical Python iteration protocol: <tt class="literal"><span class="bold"><b>for y in x...</b></span></tt> is as follows:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> iter</span><span class="special"> =</span><span class="identifier"> x</span><span class="special">.</span><span class="identifier">__iter__</span><span class="special">()</span>#<span class="identifier"> get</span><span class="identifier"> iterator</span><span class="keyword">
try</span><span class="special">:</span><span class="keyword">
while</span><span class="number"> 1</span><span class="special">:</span><span class="identifier">
y</span><span class="special"> =</span><span class="identifier"> iter</span><span class="special">.</span><span class="identifier">next</span><span class="special">()</span>#<span class="identifier"> get</span><span class="identifier"> each</span><span class="identifier"> item</span><span class="special">
...</span>#<span class="identifier"> process</span><span class="identifier"> y</span><span class="identifier">
except</span><span class="identifier"> StopIteration</span><span class="special">:</span><span class="identifier"> pass</span>#<span class="identifier"> iterator</span><span class="identifier"> exhausted</span></tt></pre><p>
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:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> object</span><span class="identifier"> get_iterator</span><span class="special"> =</span><span class="identifier"> iterator</span><span class="special">&lt;</span><span class="identifier">vector</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;</span><span class="special"> &gt;();</span><span class="identifier">
object</span><span class="identifier"> iter</span><span class="special"> =</span><span class="identifier"> get_iterator</span><span class="special">(</span><span class="identifier">v</span><span class="special">);</span><span class="identifier">
object</span><span class="identifier"> first</span><span class="special"> =</span><span class="identifier"> iter</span><span class="special">.</span><span class="identifier">next</span><span class="special">();</span></tt></pre><p>
Or for use in class_&lt;&gt;:</p><pre class="programlisting"><tt class="literal"><span class="special"> .</span><span class="identifier">def</span><span class="special">(</span><span class="string">"__iter__"</span><span class="special">,</span><span class="identifier"> iterator</span><span class="special">&lt;</span><span class="identifier">vector</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;</span><span class="special"> &gt;())</span></tt></pre><p><span class="bold"><b>range</b></span></p><p>
We can create a Python savvy iterator using the range function:</p><div class="itemizedlist"><ul type="disc"><li>
range(start, finish)
</li><li>
range&lt;Policies,Target&gt;(start, finish)
</li></ul></div><p>
Here, start/finish may be one of:</p><div class="itemizedlist"><ul type="disc"><li>
member data pointers
</li><li>
member function pointers
</li><li>
adaptable function object (use Target parameter)
</li></ul></div><p><span class="bold"><b>iterator</b></span></p><div class="itemizedlist"><ul type="disc"><li>
iterator&lt;T, Policies&gt;()
</li></ul></div><p>
Given a container <tt class="literal">T</tt>, iterator is a shortcut that simply calls <tt class="literal">range</tt>
with &amp;T::begin, &amp;T::end.</p><p>
Let's put this into action... Here's an example from some hypothetical
bogon Particle accelerator code:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> f</span><span class="special"> =</span><span class="identifier"> Field</span><span class="special">()</span><span class="keyword">
for</span><span class="identifier"> x</span><span class="identifier"> in</span><span class="identifier"> f</span><span class="special">.</span><span class="identifier">pions</span><span class="special">:</span><span class="identifier">
smash</span><span class="special">(</span><span class="identifier">x</span><span class="special">)</span><span class="keyword">
for</span><span class="identifier"> y</span><span class="identifier"> in</span><span class="identifier"> f</span><span class="special">.</span><span class="identifier">bogons</span><span class="special">:</span><span class="identifier">
count</span><span class="special">(</span><span class="identifier">y</span><span class="special">)</span></tt></pre><p>
Now, our C++ Wrapper:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> class_</span><span class="special">&lt;</span><span class="identifier">F</span><span class="special">&gt;(</span><span class="string">"Field"</span><span class="special">)</span><span class="special">
.</span><span class="identifier">property</span><span class="special">(</span><span class="string">"pions"</span><span class="special">,</span><span class="identifier"> range</span><span class="special">(&amp;</span><span class="identifier">F</span><span class="special">::</span><span class="identifier">p_begin</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">F</span><span class="special">::</span><span class="identifier">p_end</span><span class="special">))</span><span class="special">
.</span><span class="identifier">property</span><span class="special">(</span><span class="string">"bogons"</span><span class="special">,</span><span class="identifier"> range</span><span class="special">(&amp;</span><span class="identifier">F</span><span class="special">::</span><span class="identifier">b_begin</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">F</span><span class="special">::</span><span class="identifier">b_end</span><span class="special">));</span></tt></pre></div><table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr><td align="left"></td><td align="right"><small>Copyright © 2002-2004 Joel de Guzman, David Abrahams</small></td></tr></table><hr><div class="spirit-nav"><a accesskey="p" href="boost_python.embedding.html"><img src="images/prev.png" alt="Prev"></a><a accesskey="u" href="index.html"><img src="images/up.png" alt="Up"></a><a accesskey="h" href="index.html"><img src="images/home.png" alt="Home"></a><a accesskey="n" href="boost_python.exception.html"><img src="images/next.png" alt="Next"></a></div></body></html>

View File

@@ -1,135 +0,0 @@
<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title> Object Interface</title><link rel="stylesheet" href="boostbook.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="Chapter 1. Boost.Boost Python 1.0"><link rel="up" href="index.html" title="Chapter 1. Boost.Boost Python 1.0"><link rel="previous" href="boost_python.functions.html" title="Functions"><link rel="next" href="boost_python.embedding.html" title="Embedding"><link rel="chapter" href="index.html" title="Chapter 1. Boost.Boost Python 1.0"><link rel="subsection" href="boost_python.object.html#boost_python.basic_interface" title="Basic Interface"><link rel="subsection" href="boost_python.object.html#boost_python.derived_object_types" title="Derived Object types"><link rel="subsection" href="boost_python.object.html#boost_python.extracting_c___objects" title="Extracting C++ objects"><link rel="subsection" href="boost_python.object.html#boost_python.enums" title="Enums"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><table cellpadding="2" width="100%"><td valign="top"><img src="../../../../../../boost.png" alt="boost.png (6897 bytes)" width="277" height="86"></td><td align="center"><a href="../../index.htm">Home</a></td><td align="center"><a href="libraries.html">Libraries</a></td><td align="center"><a href="../../people/people.htm">People</a></td><td align="center"><a href="../../more/faq.htm">FAQ</a></td><td align="center"><a href="../../more/index.htm">More</a></td></table><hr><div class="spirit-nav"><a accesskey="p" href="boost_python.functions.html"><img src="images/prev.png" alt="Prev"></a><a accesskey="u" href="index.html"><img src="images/up.png" alt="Up"></a><a accesskey="h" href="index.html"><img src="images/home.png" alt="Home"></a><a accesskey="n" href="boost_python.embedding.html"><img src="images/next.png" alt="Next"></a></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="boost_python.object"></a> Object Interface</h2></div></div><div></div></div><div class="toc"><dl><dt><span class="section"><a href="boost_python.object.html#boost_python.basic_interface">Basic Interface</a></span></dt><dt><span class="section"><a href="boost_python.object.html#boost_python.derived_object_types">Derived Object types</a></span></dt><dt><span class="section"><a href="boost_python.object.html#boost_python.extracting_c___objects">Extracting C++ objects</a></span></dt><dt><span class="section"><a href="boost_python.object.html#boost_python.enums">Enums</a></span></dt></dl></div><p>
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 <tt class="literal">object</tt>. We shall see in
this chapter how to deal with Python objects.</p><p>
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++ <tt class="literal">object</tt>s are as close as possible to Python. This
should minimize the learning curve significantly.</p><p><span class="inlinemediaobject"><img src="images/python.png"></span></p><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="boost_python.basic_interface"></a>Basic Interface</h3></div></div><div></div></div><p>
Class <tt class="literal">object</tt> wraps <tt class="literal">PyObject*</tt>. All the intricacies of dealing with
<tt class="literal">PyObject</tt>s such as managing reference counting are handled by the
<tt class="literal">object</tt> class. C++ object interoperability is seamless. Boost.Python C++
<tt class="literal">object</tt>s can in fact be explicitly constructed from any C++ object.</p><p>
To illustrate, this Python code snippet:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> def</span><span class="identifier"> f</span><span class="special">(</span><span class="identifier">x</span><span class="special">,</span><span class="identifier"> y</span><span class="special">):</span><span class="keyword">
if</span><span class="special"> (</span><span class="identifier">y</span><span class="special"> ==</span><span class="char"> 'foo'</span><span class="special">):</span><span class="identifier">
x</span><span class="special">[</span><span class="number">3</span><span class="special">:</span><span class="number">7</span><span class="special">]</span><span class="special"> =</span><span class="char"> 'bar'</span><span class="keyword">
else</span><span class="special">:</span><span class="identifier">
x</span><span class="special">.</span><span class="identifier">items</span><span class="special"> +=</span><span class="identifier"> y</span><span class="special">(</span><span class="number">3</span><span class="special">,</span><span class="identifier"> x</span><span class="special">)</span><span class="keyword">
return</span><span class="identifier"> x</span><span class="identifier">
def</span><span class="identifier"> getfunc</span><span class="special">():</span><span class="keyword">
return</span><span class="identifier"> f</span><span class="special">;</span></tt></pre><p>
Can be rewritten in C++ using Boost.Python facilities this way:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> object</span><span class="identifier"> f</span><span class="special">(</span><span class="identifier">object</span><span class="identifier"> x</span><span class="special">,</span><span class="identifier"> object</span><span class="identifier"> y</span><span class="special">)</span><span class="special"> {</span><span class="keyword">
if</span><span class="special"> (</span><span class="identifier">y</span><span class="special"> ==</span><span class="string"> "foo"</span><span class="special">)</span><span class="identifier">
x</span><span class="special">.</span><span class="identifier">slice</span><span class="special">(</span><span class="number">3</span><span class="special">,</span><span class="number">7</span><span class="special">)</span><span class="special"> =</span><span class="string"> "bar"</span><span class="special">;</span><span class="keyword">
else</span><span class="identifier">
x</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"items"</span><span class="special">)</span><span class="special"> +=</span><span class="identifier"> y</span><span class="special">(</span><span class="number">3</span><span class="special">,</span><span class="identifier"> x</span><span class="special">);</span><span class="keyword">
return</span><span class="identifier"> x</span><span class="special">;</span><span class="special">
}</span><span class="identifier">
object</span><span class="identifier"> getfunc</span><span class="special">()</span><span class="special"> {</span><span class="keyword">
return</span><span class="identifier"> object</span><span class="special">(</span><span class="identifier">f</span><span class="special">);</span><span class="special">
}</span></tt></pre><p>
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.</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="boost_python.derived_object_types"></a>Derived Object types</h3></div></div><div></div></div><p>
Boost.Python comes with a set of derived <tt class="literal">object</tt> types corresponding to
that of Python's:</p><div class="itemizedlist"><ul type="disc"><li>
list
</li><li>
dict
</li><li>
tuple
</li><li>
str
</li><li>
long_
</li><li>
enum
</li></ul></div><p>
These derived <tt class="literal">object</tt> types act like real Python types. For instance:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> str</span><span class="special">(</span><span class="number">1</span><span class="special">)</span><span class="special"> ==&gt;</span><span class="string"> "1"</span></tt></pre><p>
Wherever appropriate, a particular derived <tt class="literal">object</tt> has corresponding
Python type's methods. For instance, <tt class="literal">dict</tt> has a <tt class="literal">keys()</tt> method:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> d</span><span class="special">.</span><span class="identifier">keys</span><span class="special">()</span></tt></pre><p><tt class="literal">make_tuple</tt> is provided for declaring <span class="emphasis"><em>tuple literals</em></span>. Example:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> make_tuple</span><span class="special">(</span><span class="number">123</span><span class="special">,</span><span class="char"> 'D'</span><span class="special">,</span><span class="string"> "Hello, World"</span><span class="special">,</span><span class="number"> 0.0</span><span class="special">);</span></tt></pre><p>
In C++, when Boost.Python <tt class="literal">object</tt>s are used as arguments to functions,
subtype matching is required. For example, when a function <tt class="literal">f</tt>, as
declared below, is wrapped, it will only accept instances of Python's
<tt class="literal">str</tt> type and subtypes.</p><pre class="programlisting"><tt class="literal"><span class="keyword"> void</span><span class="identifier"> f</span><span class="special">(</span><span class="identifier">str</span><span class="identifier"> name</span><span class="special">)</span><span class="special">
{</span><span class="identifier">
object</span><span class="identifier"> n2</span><span class="special"> =</span><span class="identifier"> name</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"upper"</span><span class="special">)();</span><span class="comment"> // NAME = name.upper()
</span><span class="identifier"> str</span><span class="identifier"> NAME</span><span class="special"> =</span><span class="identifier"> name</span><span class="special">.</span><span class="identifier">upper</span><span class="special">();</span><span class="comment"> // better
</span><span class="identifier"> object</span><span class="identifier"> msg</span><span class="special"> =</span><span class="string"> "%s is bigger than %s"</span><span class="special"> %</span><span class="identifier"> make_tuple</span><span class="special">(</span><span class="identifier">NAME</span><span class="special">,</span><span class="identifier">name</span><span class="special">);</span><span class="special">
}</span></tt></pre><p>
In finer detail:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> str</span><span class="identifier"> NAME</span><span class="special"> =</span><span class="identifier"> name</span><span class="special">.</span><span class="identifier">upper</span><span class="special">();</span></tt></pre><p>
Illustrates that we provide versions of the str type's methods as C++
member functions.</p><pre class="programlisting"><tt class="literal"><span class="identifier"> object</span><span class="identifier"> msg</span><span class="special"> =</span><span class="string"> "%s is bigger than %s"</span><span class="special"> %</span><span class="identifier"> make_tuple</span><span class="special">(</span><span class="identifier">NAME</span><span class="special">,</span><span class="identifier">name</span><span class="special">);</span></tt></pre><p>
Demonstrates that you can write the C++ equivalent of <tt class="literal">"format" % x,y,z</tt>
in Python, which is useful since there's no easy way to do that in std C++.</p><p><span class="inlinemediaobject"><img src="images/alert.gif"></span><span class="bold"><b>Beware</b></span> the common pitfall of forgetting that the constructors
of most of Python's mutable types make copies, just as in Python.</p><p>
Python:</p><pre class="programlisting"><tt class="literal"><span class="special"> &gt;&gt;&gt;</span><span class="identifier"> d</span><span class="special"> =</span><span class="identifier"> dict</span><span class="special">(</span><span class="identifier">x</span><span class="special">.</span><span class="identifier">__dict__</span><span class="special">)</span>#<span class="identifier"> copies</span><span class="identifier"> x</span><span class="special">.</span><span class="identifier">__dict__</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> d</span><span class="special">[</span><span class="char">'whatever'</span><span class="special">]</span>#<span class="identifier"> modifies</span><span class="identifier"> the</span><span class="identifier"> copy</span></tt></pre><p>
C++:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> dict</span><span class="identifier"> d</span><span class="special">(</span><span class="identifier">x</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"__dict__"</span><span class="special">));</span>#<span class="identifier"> copies</span><span class="identifier"> x</span><span class="special">.</span><span class="identifier">__dict__</span><span class="identifier">
d</span><span class="special">[</span><span class="char">'whatever'</span><span class="special">]</span><span class="special"> =</span><span class="number"> 3</span><span class="special">;</span>#<span class="identifier"> modifies</span><span class="identifier"> the</span><span class="identifier"> copy</span></tt></pre><a name="derived_object_types.class__lt_t_gt__as_objects"></a><h2><a name="id413642"></a>class_&lt;T&gt; as objects</h2><p>
Due to the dynamic nature of Boost.Python objects, any <tt class="literal">class_&lt;T&gt;</tt> may
also be one of these types! The following code snippet wraps the class
(type) object.</p><p>
We can use this to create wrapped instances. Example:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> object</span><span class="identifier"> vec345</span><span class="special"> =</span><span class="special"> (</span><span class="identifier">
class_</span><span class="special">&lt;</span><span class="identifier">Vec2</span><span class="special">&gt;(</span><span class="string">"Vec2"</span><span class="special">,</span><span class="identifier"> init</span><span class="special">&lt;</span><span class="keyword">double</span><span class="special">,</span><span class="keyword"> double</span><span class="special">&gt;())</span><span class="special">
.</span><span class="identifier">def_readonly</span><span class="special">(</span><span class="string">"length"</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">Point</span><span class="special">::</span><span class="identifier">length</span><span class="special">)</span><span class="special">
.</span><span class="identifier">def_readonly</span><span class="special">(</span><span class="string">"angle"</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">Point</span><span class="special">::</span><span class="identifier">angle</span><span class="special">)</span><span class="special">
)(</span><span class="number">3.0</span><span class="special">,</span><span class="number"> 4.0</span><span class="special">);</span><span class="identifier">
assert</span><span class="special">(</span><span class="identifier">vec345</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"length"</span><span class="special">)</span><span class="special"> ==</span><span class="number"> 5.0</span><span class="special">);</span></tt></pre></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="boost_python.extracting_c___objects"></a>Extracting C++ objects</h3></div></div><div></div></div><p>
At some point, we will need to get C++ values out of object instances. This
can be achieved with the <tt class="literal">extract&lt;T&gt;</tt> function. Consider the following:</p><pre class="programlisting"><tt class="literal"><span class="keyword"> double</span><span class="identifier"> x</span><span class="special"> =</span><span class="identifier"> o</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"length"</span><span class="special">);</span><span class="comment"> // compile error
</span></tt></pre><p>
In the code above, we got a compiler error because Boost.Python
<tt class="literal">object</tt> can't be implicitly converted to <tt class="literal">double</tt>s. Instead, what
we wanted to do above can be achieved by writing:</p><pre class="programlisting"><tt class="literal"><span class="keyword"> double</span><span class="identifier"> l</span><span class="special"> =</span><span class="identifier"> extract</span><span class="special">&lt;</span><span class="keyword">double</span><span class="special">&gt;(</span><span class="identifier">o</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"length"</span><span class="special">));</span><span class="identifier">
Vec2</span><span class="special">&amp;</span><span class="identifier"> v</span><span class="special"> =</span><span class="identifier"> extract</span><span class="special">&lt;</span><span class="identifier">Vec2</span><span class="special">&amp;&gt;(</span><span class="identifier">o</span><span class="special">);</span><span class="identifier">
assert</span><span class="special">(</span><span class="identifier">l</span><span class="special"> ==</span><span class="identifier"> v</span><span class="special">.</span><span class="identifier">length</span><span class="special">());</span></tt></pre><p>
The first line attempts to extract the "length" attribute of the
Boost.Python <tt class="literal">object</tt><tt class="literal">o</tt>. The second line attempts to <span class="emphasis"><em>extract</em></span> the
<tt class="literal">Vec2</tt> object from held by the Boost.Python <tt class="literal">object</tt><tt class="literal">o</tt>.</p><p>
Take note that we said "attempt to" above. What if the Boost.Python
<tt class="literal">object</tt><tt class="literal">o</tt> does not really hold a <tt class="literal">Vec2</tt> type? This is certainly
a possibility considering the dynamic nature of Python <tt class="literal">object</tt>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:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> extract</span><span class="special">&lt;</span><span class="identifier">Vec2</span><span class="special">&amp;&gt;</span><span class="identifier"> x</span><span class="special">(</span><span class="identifier">o</span><span class="special">);</span><span class="keyword">
if</span><span class="special"> (</span><span class="identifier">x</span><span class="special">.</span><span class="identifier">check</span><span class="special">())</span><span class="special"> {</span><span class="identifier">
Vec2</span><span class="special">&amp;</span><span class="identifier"> v</span><span class="special"> =</span><span class="identifier"> x</span><span class="special">();</span><span class="special"> ...</span></tt></pre><p><span class="inlinemediaobject"><img src="images/bulb.gif"></span> The astute reader might have noticed that the <tt class="literal">extract&lt;T&gt;</tt>
facility in fact solves the mutable copying problem:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> dict</span><span class="identifier"> d</span><span class="special"> =</span><span class="identifier"> extract</span><span class="special">&lt;</span><span class="identifier">dict</span><span class="special">&gt;(</span><span class="identifier">x</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"__dict__"</span><span class="special">));</span><span class="identifier">
d</span><span class="special">[</span><span class="char">'whatever'</span><span class="special">]</span><span class="special"> =</span><span class="number"> 3</span><span class="special">;</span>#<span class="identifier"> modifies</span><span class="identifier"> x</span><span class="special">.</span><span class="identifier">__dict__</span><span class="special"> !</span></tt></pre></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="boost_python.enums"></a>Enums</h3></div></div><div></div></div><p>
Boost.Python has a nifty facility to capture and wrap C++ enums. While
Python has no <tt class="literal">enum</tt> type, we'll often want to expose our C++ enums to
Python as an <tt class="literal">int</tt>. 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:</p><pre class="programlisting"><tt class="literal"><span class="keyword"> enum</span><span class="identifier"> choice</span><span class="special"> {</span><span class="identifier"> red</span><span class="special">,</span><span class="identifier"> blue</span><span class="special"> };</span></tt></pre><p>
the construct:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> enum_</span><span class="special">&lt;</span><span class="identifier">choice</span><span class="special">&gt;(</span><span class="string">"choice"</span><span class="special">)</span><span class="special">
.</span><span class="identifier">value</span><span class="special">(</span><span class="string">"red"</span><span class="special">,</span><span class="identifier"> red</span><span class="special">)</span><span class="special">
.</span><span class="identifier">value</span><span class="special">(</span><span class="string">"blue"</span><span class="special">,</span><span class="identifier"> blue</span><span class="special">)</span><span class="special">
;</span></tt></pre><p>
can be used to expose to Python. The new enum type is created in the
current <tt class="literal">scope()</tt>, which is usually the current module. The snippet above
creates a Python class derived from Python's <tt class="literal">int</tt> type which is
associated with the C++ type passed as its first parameter.</p><div class="informaltable"><table class="table"><colgroup><col></colgroup><tbody><tr><td><span class="inlinemediaobject"><img src="images/lens.gif"></span><span class="bold"><b>what is a scope?</b></span><p></p><p></p>
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 <a href="../../v2/scope.html" target="_top">
here</a>.</td></tr></tbody></table></div><p>
You can access those values in Python as</p><pre class="programlisting"><tt class="literal"><span class="special"> &gt;&gt;&gt;</span><span class="identifier"> my_module</span><span class="special">.</span><span class="identifier">choice</span><span class="special">.</span><span class="identifier">red</span><span class="identifier">
my_module</span><span class="special">.</span><span class="identifier">choice</span><span class="special">.</span><span class="identifier">red</span></tt></pre><p>
where my_module is the module where the enum is declared. You can also
create a new scope around a class:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> scope</span><span class="identifier"> in_X</span><span class="special"> =</span><span class="identifier"> class_</span><span class="special">&lt;</span><span class="identifier">X</span><span class="special">&gt;(</span><span class="string">"X"</span><span class="special">)</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="special"> ...</span><span class="special"> )</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="special"> ...</span><span class="special"> )</span><span class="special">
;</span><span class="comment">
// Expose X::nested as X.nested
</span><span class="identifier"> enum_</span><span class="special">&lt;</span><span class="identifier">X</span><span class="special">::</span><span class="identifier">nested</span><span class="special">&gt;(</span><span class="string">"nested"</span><span class="special">)</span><span class="special">
.</span><span class="identifier">value</span><span class="special">(</span><span class="string">"red"</span><span class="special">,</span><span class="identifier"> red</span><span class="special">)</span><span class="special">
.</span><span class="identifier">value</span><span class="special">(</span><span class="string">"blue"</span><span class="special">,</span><span class="identifier"> blue</span><span class="special">)</span><span class="special">
;</span></tt></pre></div></div><table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr><td align="left"></td><td align="right"><small>Copyright © 2002-2004 Joel de Guzman, David Abrahams</small></td></tr></table><hr><div class="spirit-nav"><a accesskey="p" href="boost_python.functions.html"><img src="images/prev.png" alt="Prev"></a><a accesskey="u" href="index.html"><img src="images/up.png" alt="Up"></a><a accesskey="h" href="index.html"><img src="images/home.png" alt="Home"></a><a accesskey="n" href="boost_python.embedding.html"><img src="images/next.png" alt="Next"></a></div></body></html>

View File

@@ -1,227 +0,0 @@
<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title> General Techniques</title><link rel="stylesheet" href="boostbook.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="Chapter 1. Boost.Boost Python 1.0"><link rel="up" href="index.html" title="Chapter 1. Boost.Boost Python 1.0"><link rel="previous" href="boost_python.exception.html" title=" Exception Translation"><link rel="chapter" href="index.html" title="Chapter 1. Boost.Boost Python 1.0"><link rel="subsection" href="boost_python.techniques.html#boost_python.creating_packages" title="Creating Packages"><link rel="subsection" href="boost_python.techniques.html#boost_python.extending_wrapped_objects_in_python" title="Extending Wrapped Objects in Python"><link rel="subsection" href="boost_python.techniques.html#boost_python.reducing_compiling_time" title="Reducing Compiling Time"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><table cellpadding="2" width="100%"><td valign="top"><img src="../../../../../../boost.png" alt="boost.png (6897 bytes)" width="277" height="86"></td><td align="center"><a href="../../index.htm">Home</a></td><td align="center"><a href="libraries.html">Libraries</a></td><td align="center"><a href="../../people/people.htm">People</a></td><td align="center"><a href="../../more/faq.htm">FAQ</a></td><td align="center"><a href="../../more/index.htm">More</a></td></table><hr><div class="spirit-nav"><a accesskey="p" href="boost_python.exception.html"><img src="images/prev.png" alt="Prev"></a><a accesskey="u" href="index.html"><img src="images/up.png" alt="Up"></a><a accesskey="h" href="index.html"><img src="images/home.png" alt="Home"></a></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="boost_python.techniques"></a> General Techniques</h2></div></div><div></div></div><div class="toc"><dl><dt><span class="section"><a href="boost_python.techniques.html#boost_python.creating_packages">Creating Packages</a></span></dt><dt><span class="section"><a href="boost_python.techniques.html#boost_python.extending_wrapped_objects_in_python">Extending Wrapped Objects in Python</a></span></dt><dt><span class="section"><a href="boost_python.techniques.html#boost_python.reducing_compiling_time">Reducing Compiling Time</a></span></dt></dl></div><p>
Here are presented some useful techniques that you can use while wrapping code with Boost.Python.</p><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="boost_python.creating_packages"></a>Creating Packages</h3></div></div><div></div></div><p>
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
<a href="http://www.python.org/doc/current/tut/node8.html" target="_top">
Python Tutorial</a>.</p><p>
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.</p><p>
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)
<tt class="literal">sounds</tt>. Our library already has a neat C++ namespace hierarchy, like so:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> sounds</span><span class="special">::</span><span class="identifier">core</span><span class="identifier">
sounds</span><span class="special">::</span><span class="identifier">io</span><span class="identifier">
sounds</span><span class="special">::</span><span class="identifier">filters</span></tt></pre><p>
We would like to present this same hierarchy to the Python user, allowing him
to write code like this:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> import</span><span class="identifier"> sounds</span><span class="special">.</span><span class="identifier">filters</span><span class="identifier">
sounds</span><span class="special">.</span><span class="identifier">filters</span><span class="special">.</span><span class="identifier">echo</span><span class="special">(...)</span>#<span class="identifier"> echo</span><span class="identifier"> is</span><span class="identifier"> a</span><span class="identifier"> C</span><span class="special">++</span><span class="identifier"> function</span></tt></pre><p>
The first step is to write the wrapping code. We have to export each module
separately with Boost.Python, like this:</p><pre class="programlisting"><tt class="literal"><span class="comment"> /* file core.cpp */</span><span class="identifier">
BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">core</span><span class="special">)</span><span class="special">
{</span><span class="comment">
/* export everything in the sounds::core namespace */</span><span class="special">
...</span><span class="special">
}</span><span class="comment">
/* file io.cpp */</span><span class="identifier">
BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">io</span><span class="special">)</span><span class="special">
{</span><span class="comment">
/* export everything in the sounds::io namespace */</span><span class="special">
...</span><span class="special">
}</span><span class="comment">
/* file filters.cpp */</span><span class="identifier">
BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">filters</span><span class="special">)</span><span class="special">
{</span><span class="comment">
/* export everything in the sounds::filters namespace */</span><span class="special">
...</span><span class="special">
}</span></tt></pre><p>
Compiling these files will generate the following Python extensions:
<tt class="literal">core.pyd</tt>, <tt class="literal">io.pyd</tt> and <tt class="literal">filters.pyd</tt>.</p><div class="informaltable"><table class="table"><colgroup><col></colgroup><tbody><tr><td><span class="inlinemediaobject"><img src="images/note.gif"></span> The extension <tt class="literal">.pyd</tt> is used for python extension modules, which
are just shared libraries. Using the default for your system, like <tt class="literal">.so</tt> for
Unix and <tt class="literal">.dll</tt> for Windows, works just as well.</td></tr></tbody></table></div><p>
Now, we create this directory structure for our Python package:</p><pre class="programlisting"><tt class="literal"> sounds/
__init__.py
core.pyd
filters.pyd
io.pyd
</tt></pre><p>
The file <tt class="literal">__init__.py</tt> is what tells Python that the directory <tt class="literal">sounds/</tt> is
actually a Python package. It can be a empty file, but can also perform some
magic, that will be shown later.</p><p>
Now our package is ready. All the user has to do is put <tt class="literal">sounds</tt> into his
<a href="http://www.python.org/doc/current/tut/node8.html#SECTION008110000000000000000" target="_top">
PYTHONPATH</a> and fire up the interpreter:</p><pre class="programlisting"><tt class="literal"><span class="special"> &gt;&gt;&gt;</span><span class="identifier"> import</span><span class="identifier"> sounds</span><span class="special">.</span><span class="identifier">io</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> import</span><span class="identifier"> sounds</span><span class="special">.</span><span class="identifier">filters</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> sound</span><span class="special"> =</span><span class="identifier"> sounds</span><span class="special">.</span><span class="identifier">io</span><span class="special">.</span><span class="identifier">open</span><span class="special">(</span><span class="char">'file.mp3'</span><span class="special">)</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> new_sound</span><span class="special"> =</span><span class="identifier"> sounds</span><span class="special">.</span><span class="identifier">filters</span><span class="special">.</span><span class="identifier">echo</span><span class="special">(</span><span class="identifier">sound</span><span class="special">,</span><span class="number"> 1.0</span><span class="special">)</span></tt></pre><p>
Nice heh?</p><p>
This is the simplest way to create hierarchies of packages, but it is not very
flexible. What if we want to add a <span class="emphasis"><em>pure</em></span> 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.</p><p>
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:</p><pre class="programlisting"><tt class="literal"><span class="comment"> /* file core.cpp */</span><span class="identifier">
BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">_core</span><span class="special">)</span><span class="special">
{</span><span class="special">
...</span><span class="comment">
/* export everything in the sounds::core namespace */</span><span class="special">
}</span></tt></pre><p>
Note that we added an underscore to the module name. The filename will have to
be changed to <tt class="literal">_core.pyd</tt> as well, and we do the same to the other extension modules.
Now, we change our package hierarchy like so:</p><pre class="programlisting"><tt class="literal"> sounds/
__init__.py
core/
__init__.py
_core.pyd
filters/
__init__.py
_filters.pyd
io/
__init__.py
_io.pyd
</tt></pre><p>
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:</p><pre class="programlisting"><tt class="literal"><span class="special"> &gt;&gt;&gt;</span><span class="identifier"> import</span><span class="identifier"> sounds</span><span class="special">.</span><span class="identifier">core</span><span class="special">.</span><span class="identifier">_core</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> sounds</span><span class="special">.</span><span class="identifier">core</span><span class="special">.</span><span class="identifier">_core</span><span class="special">.</span><span class="identifier">foo</span><span class="special">(...)</span></tt></pre><p>
which is not what we want. But here enters the <tt class="literal">__init__.py</tt> magic: everything
that is brought to the <tt class="literal">__init__.py</tt> namespace can be accessed directly by the
user. So, all we have to do is bring the entire namespace from <tt class="literal">_core.pyd</tt>
to <tt class="literal">core/__init__.py</tt>. So add this line of code to <tt class="literal">sounds/core/__init__.py</tt>:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> from</span><span class="identifier"> _core</span><span class="identifier"> import</span><span class="special"> *</span></tt></pre><p>
We do the same for the other packages. Now the user accesses the functions and
classes in the extension modules like before:</p><pre class="programlisting"><tt class="literal"><span class="special"> &gt;&gt;&gt;</span><span class="identifier"> import</span><span class="identifier"> sounds</span><span class="special">.</span><span class="identifier">filters</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> sounds</span><span class="special">.</span><span class="identifier">filters</span><span class="special">.</span><span class="identifier">echo</span><span class="special">(...)</span></tt></pre><p>
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 <span class="emphasis"><em>pure</em></span> Python function,
<tt class="literal">echo_noise</tt>, to the <tt class="literal">filters</tt> package. This function applies both the
<tt class="literal">echo</tt> and <tt class="literal">noise</tt> filters in sequence in the given <tt class="literal">sound</tt> object. We
create a file named <tt class="literal">sounds/filters/echo_noise.py</tt> and code our function:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> import</span><span class="identifier"> _filters</span><span class="identifier">
def</span><span class="identifier"> echo_noise</span><span class="special">(</span><span class="identifier">sound</span><span class="special">):</span><span class="identifier">
s</span><span class="special"> =</span><span class="identifier"> _filters</span><span class="special">.</span><span class="identifier">echo</span><span class="special">(</span><span class="identifier">sound</span><span class="special">)</span><span class="identifier">
s</span><span class="special"> =</span><span class="identifier"> _filters</span><span class="special">.</span><span class="identifier">noise</span><span class="special">(</span><span class="identifier">sound</span><span class="special">)</span><span class="keyword">
return</span><span class="identifier"> s</span></tt></pre><p>
Next, we add this line to <tt class="literal">sounds/filters/__init__.py</tt>:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> from</span><span class="identifier"> echo_noise</span><span class="identifier"> import</span><span class="identifier"> echo_noise</span></tt></pre><p>
And that's it. The user now accesses this function like any other function
from the <tt class="literal">filters</tt> package:</p><pre class="programlisting"><tt class="literal"><span class="special"> &gt;&gt;&gt;</span><span class="identifier"> import</span><span class="identifier"> sounds</span><span class="special">.</span><span class="identifier">filters</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> sounds</span><span class="special">.</span><span class="identifier">filters</span><span class="special">.</span><span class="identifier">echo_noise</span><span class="special">(...)</span></tt></pre></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="boost_python.extending_wrapped_objects_in_python"></a>Extending Wrapped Objects in Python</h3></div></div><div></div></div><p>
Thanks to Python's flexibility, you can easily add new methods to a class,
even after it was already created:</p><pre class="programlisting"><tt class="literal"><span class="special"> &gt;&gt;&gt;</span><span class="keyword"> class</span><span class="identifier"> C</span><span class="special">(</span><span class="identifier">object</span><span class="special">):</span><span class="identifier"> pass</span><span class="special">
&gt;&gt;&gt;</span><span class="special">
&gt;&gt;&gt;</span>#<span class="identifier"> a</span><span class="identifier"> regular</span><span class="identifier"> function</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> def</span><span class="identifier"> C_str</span><span class="special">(</span><span class="identifier">self</span><span class="special">):</span><span class="keyword"> return</span><span class="char"> 'A C instance!'</span><span class="special">
&gt;&gt;&gt;</span><span class="special">
&gt;&gt;&gt;</span>#<span class="identifier"> now</span><span class="identifier"> we</span><span class="identifier"> turn</span><span class="identifier"> it</span><span class="identifier"> in</span><span class="identifier"> a</span><span class="identifier"> member</span><span class="identifier"> function</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> C</span><span class="special">.</span><span class="identifier">__str__</span><span class="special"> =</span><span class="identifier"> C_str</span><span class="special">
&gt;&gt;&gt;</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> c</span><span class="special"> =</span><span class="identifier"> C</span><span class="special">()</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> print</span><span class="identifier"> c</span><span class="identifier">
A</span><span class="identifier"> C</span><span class="identifier"> instance</span><span class="special">!</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> C_str</span><span class="special">(</span><span class="identifier">c</span><span class="special">)</span><span class="identifier">
A</span><span class="identifier"> C</span><span class="identifier"> instance</span><span class="special">!</span></tt></pre><p>
Yes, Python rox. <span class="inlinemediaobject"><img src="images/smiley.gif"></span></p><p>
We can do the same with classes that were wrapped with Boost.Python. Suppose
we have a class <tt class="literal">point</tt> in C++:</p><pre class="programlisting"><tt class="literal"><span class="keyword"> class</span><span class="identifier"> point</span><span class="special"> {...};</span><span class="identifier">
BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">_geom</span><span class="special">)</span><span class="special">
{</span><span class="identifier">
class_</span><span class="special">&lt;</span><span class="identifier">point</span><span class="special">&gt;(</span><span class="string">"point"</span><span class="special">)...;</span><span class="special">
}</span></tt></pre><p>
If we are using the technique from the previous session,
<a href="creating_packages.html" target="_top">
Creating Packages</a>, we can code directly into <tt class="literal">geom/__init__.py</tt>:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> from</span><span class="identifier"> _geom</span><span class="identifier"> import</span><span class="special"> *</span>#<span class="identifier"> a</span><span class="identifier"> regular</span><span class="identifier"> function</span><span class="identifier">
def</span><span class="identifier"> point_str</span><span class="special">(</span><span class="identifier">self</span><span class="special">):</span><span class="keyword">
return</span><span class="identifier"> str</span><span class="special">((</span><span class="identifier">self</span><span class="special">.</span><span class="identifier">x</span><span class="special">,</span><span class="identifier"> self</span><span class="special">.</span><span class="identifier">y</span><span class="special">))</span>#<span class="identifier"> now</span><span class="identifier"> we</span><span class="identifier"> turn</span><span class="identifier"> it</span><span class="identifier"> into</span><span class="identifier"> a</span><span class="identifier"> member</span><span class="identifier"> function</span><span class="identifier">
point</span><span class="special">.</span><span class="identifier">__str__</span><span class="special"> =</span><span class="identifier"> point_str</span></tt></pre><p><span class="bold"><b>All</b></span> point instances created from C++ will also have this member function!
This technique has several advantages:</p><div class="itemizedlist"><ul type="disc"><li>
Cut down compile times to zero for these additional functions
</li><li>
Reduce the memory footprint to virtually zero
</li><li>
Minimize the need to recompile
</li><li>
Rapid prototyping (you can move the code to C++ if required without changing the interface)
</li></ul></div><p>
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.</p><pre class="programlisting"><tt class="literal">
#<span class="identifier"> The</span><span class="identifier"> one</span><span class="identifier"> Boost</span><span class="special">.</span><span class="identifier">Python</span><span class="identifier"> uses</span><span class="keyword"> for</span><span class="identifier"> all</span><span class="identifier"> wrapped</span><span class="identifier"> classes</span><span class="special">.</span>#<span class="identifier"> You</span><span class="identifier"> can</span><span class="identifier"> use</span><span class="identifier"> here</span><span class="identifier"> any</span><span class="keyword"> class</span><span class="identifier"> exported</span><span class="identifier"> by</span><span class="identifier"> Boost</span><span class="identifier"> instead</span><span class="identifier"> of</span><span class="string"> "point"</span><span class="identifier">
BoostPythonMetaclass</span><span class="special"> =</span><span class="identifier"> point</span><span class="special">.</span><span class="identifier">__class__</span><span class="keyword">
class</span><span class="identifier"> injector</span><span class="special">(</span><span class="identifier">object</span><span class="special">):</span><span class="keyword">
class</span><span class="identifier"> __metaclass__</span><span class="special">(</span><span class="identifier">BoostPythonMetaclass</span><span class="special">):</span><span class="identifier">
def</span><span class="identifier"> __init__</span><span class="special">(</span><span class="identifier">self</span><span class="special">,</span><span class="identifier"> name</span><span class="special">,</span><span class="identifier"> bases</span><span class="special">,</span><span class="identifier"> dict</span><span class="special">):</span><span class="keyword">
for</span><span class="identifier"> b</span><span class="identifier"> in</span><span class="identifier"> bases</span><span class="special">:</span><span class="keyword">
if</span><span class="identifier"> type</span><span class="special">(</span><span class="identifier">b</span><span class="special">)</span><span class="keyword"> not</span><span class="identifier"> in</span><span class="special"> (</span><span class="identifier">self</span><span class="special">,</span><span class="identifier"> type</span><span class="special">):</span><span class="keyword">
for</span><span class="identifier"> k</span><span class="special">,</span><span class="identifier">v</span><span class="identifier"> in</span><span class="identifier"> dict</span><span class="special">.</span><span class="identifier">items</span><span class="special">():</span><span class="identifier">
setattr</span><span class="special">(</span><span class="identifier">b</span><span class="special">,</span><span class="identifier">k</span><span class="special">,</span><span class="identifier">v</span><span class="special">)</span><span class="keyword">
return</span><span class="identifier"> type</span><span class="special">.</span><span class="identifier">__init__</span><span class="special">(</span><span class="identifier">self</span><span class="special">,</span><span class="identifier"> name</span><span class="special">,</span><span class="identifier"> bases</span><span class="special">,</span><span class="identifier"> dict</span><span class="special">)</span>#<span class="identifier"> inject</span><span class="identifier"> some</span><span class="identifier"> methods</span><span class="identifier"> in</span><span class="identifier"> the</span><span class="identifier"> point</span><span class="identifier"> foo</span><span class="keyword">
class</span><span class="identifier"> more_point</span><span class="special">(</span><span class="identifier">injector</span><span class="special">,</span><span class="identifier"> point</span><span class="special">):</span><span class="identifier">
def</span><span class="identifier"> __repr__</span><span class="special">(</span><span class="identifier">self</span><span class="special">):</span><span class="keyword">
return</span><span class="char"> 'Point(x=%s, y=%s)'</span><span class="special"> %</span><span class="special"> (</span><span class="identifier">self</span><span class="special">.</span><span class="identifier">x</span><span class="special">,</span><span class="identifier"> self</span><span class="special">.</span><span class="identifier">y</span><span class="special">)</span><span class="identifier">
def</span><span class="identifier"> foo</span><span class="special">(</span><span class="identifier">self</span><span class="special">):</span><span class="identifier">
print</span><span class="char"> 'foo!'</span></tt></pre><p>
Now let's see how it got:</p><pre class="programlisting"><tt class="literal"><span class="special"> &gt;&gt;&gt;</span><span class="identifier"> print</span><span class="identifier"> point</span><span class="special">()</span><span class="identifier">
Point</span><span class="special">(</span><span class="identifier">x</span><span class="special">=</span><span class="number">10</span><span class="special">,</span><span class="identifier"> y</span><span class="special">=</span><span class="number">10</span><span class="special">)</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> point</span><span class="special">().</span><span class="identifier">foo</span><span class="special">()</span><span class="identifier">
foo</span><span class="special">!</span></tt></pre><p>
Another useful idea is to replace constructors with factory functions:</p><pre class="programlisting"><tt class="literal"><span class="identifier"> _point</span><span class="special"> =</span><span class="identifier"> point</span><span class="identifier">
def</span><span class="identifier"> point</span><span class="special">(</span><span class="identifier">x</span><span class="special">=</span><span class="number">0</span><span class="special">,</span><span class="identifier"> y</span><span class="special">=</span><span class="number">0</span><span class="special">):</span><span class="keyword">
return</span><span class="identifier"> _point</span><span class="special">(</span><span class="identifier">x</span><span class="special">,</span><span class="identifier"> y</span><span class="special">)</span></tt></pre><p>
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.</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="boost_python.reducing_compiling_time"></a>Reducing Compiling Time</h3></div></div><div></div></div><p>
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:</p><pre class="programlisting"><tt class="literal"><span class="comment"> /* file point.cpp */</span><span class="preprocessor">
#include</span><span class="special"> &lt;</span><span class="identifier">point</span><span class="special">.</span><span class="identifier">h</span><span class="special">&gt;</span><span class="preprocessor">
#include</span><span class="special"> &lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">python</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span><span class="keyword">
void</span><span class="identifier"> export_point</span><span class="special">()</span><span class="special">
{</span><span class="identifier">
class_</span><span class="special">&lt;</span><span class="identifier">point</span><span class="special">&gt;(</span><span class="string">"point"</span><span class="special">)...;</span><span class="special">
}</span><span class="comment">
/* file triangle.cpp */</span><span class="preprocessor">
#include</span><span class="special"> &lt;</span><span class="identifier">triangle</span><span class="special">.</span><span class="identifier">h</span><span class="special">&gt;</span><span class="preprocessor">
#include</span><span class="special"> &lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">python</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span><span class="keyword">
void</span><span class="identifier"> export_triangle</span><span class="special">()</span><span class="special">
{</span><span class="identifier">
class_</span><span class="special">&lt;</span><span class="identifier">triangle</span><span class="special">&gt;(</span><span class="string">"triangle"</span><span class="special">)...;</span><span class="special">
}</span></tt></pre><p>
Now you create a file <tt class="literal">main.cpp</tt>, which contains the <tt class="literal">BOOST_PYTHON_MODULE</tt>
macro, and call the various export functions inside it.</p><pre class="programlisting"><tt class="literal"><span class="keyword"> void</span><span class="identifier"> export_point</span><span class="special">();</span><span class="keyword">
void</span><span class="identifier"> export_triangle</span><span class="special">();</span><span class="identifier">
BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">_geom</span><span class="special">)</span><span class="special">
{</span><span class="identifier">
export_point</span><span class="special">();</span><span class="identifier">
export_triangle</span><span class="special">();</span><span class="special">
}</span></tt></pre><p>
Compiling and linking together all this files produces the same result as the
usual approach:</p><pre class="programlisting"><tt class="literal"><span class="preprocessor"> #include</span><span class="special"> &lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">python</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span><span class="preprocessor">
#include</span><span class="special"> &lt;</span><span class="identifier">point</span><span class="special">.</span><span class="identifier">h</span><span class="special">&gt;</span><span class="preprocessor">
#include</span><span class="special"> &lt;</span><span class="identifier">triangle</span><span class="special">.</span><span class="identifier">h</span><span class="special">&gt;</span><span class="identifier">
BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">_geom</span><span class="special">)</span><span class="special">
{</span><span class="identifier">
class_</span><span class="special">&lt;</span><span class="identifier">point</span><span class="special">&gt;(</span><span class="string">"point"</span><span class="special">)...;</span><span class="identifier">
class_</span><span class="special">&lt;</span><span class="identifier">triangle</span><span class="special">&gt;(</span><span class="string">"triangle"</span><span class="special">)...;</span><span class="special">
}</span></tt></pre><p>
but the memory is kept under control.</p><p>
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.</p><div class="informaltable"><table class="table"><colgroup><col></colgroup><tbody><tr><td><span class="inlinemediaobject"><img src="images/note.gif"></span> If you're exporting your classes with <a href="../../../pyste/index.html" target="_top">
Pyste</a>,
take a look at the <tt class="literal">--multiple</tt> option, that generates the wrappers in
various files as demonstrated here.</td></tr></tbody></table></div><div class="informaltable"><table class="table"><colgroup><col></colgroup><tbody><tr><td><span class="inlinemediaobject"><img src="images/note.gif"></span> This method is useful too if you are getting the error message
<span class="emphasis"><em>"fatal error C1204:Compiler limit:internal structure overflow"</em></span> when compiling
a large source file, as explained in the <a href="../../v2/faq.html#c1204" target="_top">
FAQ</a>.</td></tr></tbody></table></div></div></div><table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr><td align="left"></td><td align="right"><small>Copyright © 2002-2004 Joel de Guzman, David Abrahams</small></td></tr></table><hr><div class="spirit-nav"><a accesskey="p" href="boost_python.exception.html"><img src="images/prev.png" alt="Prev"></a><a accesskey="u" href="index.html"><img src="images/up.png" alt="Up"></a><a accesskey="h" href="index.html"><img src="images/home.png" alt="Home"></a></div></body></html>

View File

@@ -14,11 +14,8 @@ documentation. */
body
{
padding: 2em 1em 2em 1em;
background-color: #FFFFFF;
margin: 1em 2em 1em 2em;
margin: 1em 1em 1em 1em;
font-family: sans-serif;
color: black;
background: white;
}
/* Paragraphs */
@@ -27,32 +24,42 @@ p
text-align: justify;
}
pre.synopsis
{
margin: 1pc 4% 0pc 4%;
padding: 0.5pc 0.5pc 0.5pc 0.5pc;
}
/* Headings */
h1, h2, h3, h4, h5, h6 { text-align: left }
h1, h2, h3 { color: #005A9C; }
h1, h2, h3, h4, h5, h6 { text-align: left; margin-top: 2pc; }
h1 { font: 170% sans-serif }
h2 { font: bold 140% sans-serif }
h3 { font: 120% sans-serif }
h4 { font: bold 100% sans-serif }
h5 { font: italic 100% sans-serif }
h6 { font: small-caps 100% sans-serif }
h6 { font: italic 100% sans-serif }
/* Unordered lists */
ul
{
list-style-image: url(images/bullet.gif);
text-align: justify;
}
/* Links */
a
a
{
font-weight: bold;
color: #003366;
text-decoration: none; /* no underline */
}
a:hover
{
text-decoration: underline;
}
/* Top page title */
.title/*, .refnamediv h2, .standalone-title */
title, h1.title, h2.title, h3.title,
h4.title, h5.title, h6.title,
.refentrytitle
{
font-weight: bold;
font-size: 2pc;
@@ -71,46 +78,25 @@ a
padding-left: 0.5em;
}
/* Program listing box */
.programlisting /*, .table-programlisting*/
.spirit-nav img
{
background-color: #f5f5f5;
border: gray 1pt solid;
display: block;
padding-top: 4px;
padding-right: 4px;
padding-bottom: 4px;
padding-left: 4px;
border-width: 0px;
}
/* Syntax Highlighting */
.keyword { color: #000099}
.identifier {}
.special { color: #800040}
.preprocessor { color: #FF0000}
.char { color: #6666FF; font-style: italic}
.comment { font-style: italic; color: #990000}
.string { font-style: italic; color: #666666}
.number { color: #6666FF; font-style: italic}
.quotes { color: #666666; font-style: italic; font-weight: bold}
.copyright { color: #666666; font-size: small}
.white_bkd { background-color: #FFFFFF}
.dk_grey_bkd { background-color: #999999}
/* Literals */
tt.literal
/* Program listing box */
.programlisting, .screen
{
color: #000050
}
display: block;
margin-left: 4%;
margin-right: 4%;
padding: 0.5pc 0.5pc 0.5pc 0.5pc;
}
/* Table of contents */
.toc
{
margin-left: 15%;
margin-right: 15%;
margin-top: 1pc;
margin-bottom: 0pc;
padding: 0.5pc;
margin: 1pc 4% 0pc 4%;
padding: 0.5pc 0.5pc 0.5pc 0.5pc;
}
.boost-toc
@@ -120,46 +106,190 @@ tt.literal
}
/* Tables */
.table-title
.table-title, div.table p.title
{
color: #005A9C;
margin-left: 8%;
margin-left: 4%;
padding-right: 0.5em;
padding-left: 0.5em;
padding-left: 0.5em;
font-size: 120%;
}
.informaltable table
.informaltable table, .table table
{
margin-left: 8%;
margin-right: 8%;
width: 92%;
margin-left: 4%;
margin-right: 4%;
}
div.informaltable table
div.informaltable table, div.table table
{
background-color: white;
padding-top: 4px;
padding-right: 4px;
padding-bottom: 4px;
padding-left: 4px;
padding: 4px 4px 4px 4px;
}
div.informaltable table tr td
div.informaltable table tr td, div.table table tr td
{
background-color: #D9EFFF;
padding-top: 0.5em;
padding-right: 0.5em;
padding-bottom: 0.5em;
padding-left: 0.5em;
padding: 0.5em 0.5em 0.5em 0.5em;
text-align: justify;
}
div.informaltable table tr th, div.table table tr th
{
padding: 0.5em 0.5em 0.5em 0.5em;
border: 1pt solid white;
}
/* inlined images */
.inlinemediaobject
{
padding-top: 0.5em;
padding-right: 0.5em;
padding-bottom: 0.5em;
padding-left: 0.5em;
padding: 0.5em 0.5em 0.5em 0.5em;
}
/* tone down the title of Parameter lists */
div.variablelist p.title
{
font-weight: bold;
font-size: 100%;
text-align: left;
}
/* tabularize parameter lists */
div.variablelist dl dt
{
float: left;
clear: left;
display: block;
font-style: italic;
}
div.variablelist dl dd
{
display: block;
clear: right;
padding-left: 8pc;
}
/* title of books and articles in bibliographies */
span.title
{
font-style: italic;
}
@media screen
{
a
{
color: #005a9c;
}
a:visited
{
color: #9c5a9c;
}
/* Syntax Highlighting */
.keyword { color: #0000AA; font-weight: bold; }
.identifier {}
.special { color: #707070; }
.preprocessor { color: #402080; font-weight: bold; }
.char { color: teal; }
.comment { color: #800000; }
.string { color: teal; }
.number { color: teal; }
.copyright { color: #666666; font-size: small; }
.white_bkd { background-color: #FFFFFF; }
.dk_grey_bkd { background-color: #999999; }
pre.synopsis
{
background-color: #f3f3f3;
}
.programlisting, .screen
{
background-color: #f3f3f3;
}
/* Table of contents */
.toc
{
background-color: #f3f3f3;
}
div.informaltable table tr td, div.table table tr td
{
background-color: #F3F3F3;
border: 1pt solid white;
}
div.informaltable table tr th, div.table table tr th
{
background-color: #e4e4e4;
}
span.highlight
{
color: #00A000;
}
}
@media print
{
a
{
color: black;
}
a:visited
{
color: black;
}
.spirit-nav
{
display: none;
}
/* Syntax Highlighting */
.keyword
{
font-weight: bold;
}
pre.synopsis
{
border: 1px solid gray;
}
.programlisting, .screen
{
border: 1px solid gray;
}
/* Table of contents */
.toc
{
border: 1px solid gray;
}
.informaltable table, .table table
{
border: 1px solid gray;
border-collapse: collapse;
}
div.informaltable table tr td, div.table table tr td
{
border: 1px solid gray;
}
div.informaltable table tr th, div.table table tr th
{
border: 1px solid gray;
}
span.highlight
{
font-weight: bold;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 603 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 358 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 336 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 658 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 334 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 867 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 640 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 370 B

View File

@@ -1,7 +1,95 @@
<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>Chapter 1. Boost.Boost Python 1.0</title><link rel="stylesheet" href="boostbook.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="Chapter 1. Boost.Boost Python 1.0"><link rel="next" href="boost_python.hello.html" title=" Building Hello World"><link rel="chapter" href="index.html" title="Chapter 1. Boost.Boost Python 1.0"><link rel="section" href="index.html#boost_python.quickstart" title="QuickStart"><link rel="section" href="boost_python.hello.html" title=" Building Hello World"><link rel="section" href="boost_python.exposing.html" title=" Exposing Classes"><link rel="section" href="boost_python.functions.html" title="Functions"><link rel="section" href="boost_python.object.html" title=" Object Interface"><link rel="section" href="boost_python.embedding.html" title="Embedding"><link rel="section" href="boost_python.iterators.html" title="Iterators"><link rel="section" href="boost_python.exception.html" title=" Exception Translation"><link rel="section" href="boost_python.techniques.html" title=" General Techniques"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><table cellpadding="2" width="100%"><td valign="top"><img src="../../../../../../boost.png" alt="boost.png (6897 bytes)" width="277" height="86"></td><td align="center"><a href="../../index.htm">Home</a></td><td align="center"><a href="libraries.html">Libraries</a></td><td align="center"><a href="../../people/people.htm">People</a></td><td align="center"><a href="../../more/faq.htm">FAQ</a></td><td align="center"><a href="../../more/index.htm">More</a></td></table><hr><div class="spirit-nav"><a accesskey="n" href="boost_python.hello.html"><img src="images/next.png" alt="Next"></a></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="boost_python"></a>Chapter 1. Boost.Boost Python 1.0</h2></div><div><div class="author"><h3 class="author"><span class="firstname">Joel</span> <span class="surname">de Guzman</span></h3></div></div><div><div class="author"><h3 class="author"><span class="firstname"></span> <span class="surname">David Abrahams</span></h3></div></div><div><p class="copyright">Copyright © 2002-2004 Joel de Guzman, David Abrahams</p></div><div><div class="legalnotice"><p>Distributed under the Boost Software License, Version 1.0.
(See accompanying file <tt class="filename">LICENSE_1_0.txt</tt> or copy at
<a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
</p></div></div></div><div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="index.html#boost_python.quickstart">QuickStart</a></span></dt><dt><span class="section"><a href="boost_python.hello.html"> Building Hello World</a></span></dt><dt><span class="section"><a href="boost_python.exposing.html"> Exposing Classes</a></span></dt><dd><dl><dt><span class="section"><a href="boost_python.exposing.html#boost_python.constructors">Constructors</a></span></dt><dt><span class="section"><a href="boost_python.exposing.html#boost_python.class_data_members">Class Data Members</a></span></dt><dt><span class="section"><a href="boost_python.exposing.html#boost_python.class_properties">Class Properties</a></span></dt><dt><span class="section"><a href="boost_python.exposing.html#boost_python.inheritance">Inheritance</a></span></dt><dt><span class="section"><a href="boost_python.exposing.html#boost_python.class_virtual_functions">Class Virtual Functions</a></span></dt><dt><span class="section"><a href="boost_python.exposing.html#boost_python.deriving_a_python_class">Deriving a Python Class</a></span></dt><dt><span class="section"><a href="boost_python.exposing.html#boost_python.virtual_functions_with_default_implementations">Virtual Functions with Default Implementations</a></span></dt><dt><span class="section"><a href="boost_python.exposing.html#boost_python.class_operators_special_functions">Class Operators/Special Functions</a></span></dt></dl></dd><dt><span class="section"><a href="boost_python.functions.html">Functions</a></span></dt><dd><dl><dt><span class="section"><a href="boost_python.functions.html#boost_python.call_policies">Call Policies</a></span></dt><dt><span class="section"><a href="boost_python.functions.html#boost_python.overloading">Overloading</a></span></dt><dt><span class="section"><a href="boost_python.functions.html#boost_python.default_arguments">Default Arguments</a></span></dt><dt><span class="section"><a href="boost_python.functions.html#boost_python.auto_overloading">Auto-Overloading</a></span></dt></dl></dd><dt><span class="section"><a href="boost_python.object.html"> Object Interface</a></span></dt><dd><dl><dt><span class="section"><a href="boost_python.object.html#boost_python.basic_interface">Basic Interface</a></span></dt><dt><span class="section"><a href="boost_python.object.html#boost_python.derived_object_types">Derived Object types</a></span></dt><dt><span class="section"><a href="boost_python.object.html#boost_python.extracting_c___objects">Extracting C++ objects</a></span></dt><dt><span class="section"><a href="boost_python.object.html#boost_python.enums">Enums</a></span></dt></dl></dd><dt><span class="section"><a href="boost_python.embedding.html">Embedding</a></span></dt><dd><dl><dt><span class="section"><a href="boost_python.embedding.html#boost_python.using_the_interpreter">Using the interpreter</a></span></dt></dl></dd><dt><span class="section"><a href="boost_python.iterators.html">Iterators</a></span></dt><dt><span class="section"><a href="boost_python.exception.html"> Exception Translation</a></span></dt><dt><span class="section"><a href="boost_python.techniques.html"> General Techniques</a></span></dt><dd><dl><dt><span class="section"><a href="boost_python.techniques.html#boost_python.creating_packages">Creating Packages</a></span></dt><dt><span class="section"><a href="boost_python.techniques.html#boost_python.extending_wrapped_objects_in_python">Extending Wrapped Objects in Python</a></span></dt><dt><span class="section"><a href="boost_python.techniques.html#boost_python.reducing_compiling_time">Reducing Compiling Time</a></span></dt></dl></dd></dl></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="boost_python.quickstart"></a>QuickStart</h2></div></div><div></div></div><p>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Chapter 1. python 1.0</title>
<link rel="stylesheet" href="boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.65.1">
<link rel="home" href="index.html" title="Chapter 1. python 1.0">
<link rel="next" href="python/hello.html" title=" Building Hello World">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%">
<td valign="top"><img alt="boost.png (6897 bytes)" width="277" height="86" src="../../boost.png"></td>
<td align="center"><a href="../../index.htm">Home</a></td>
<td align="center"><a href="libraries.html">Libraries</a></td>
<td align="center"><a href="../../people/people.htm">People</a></td>
<td align="center"><a href="../../more/faq.htm">FAQ</a></td>
<td align="center"><a href="../../more/index.htm">More</a></td>
</table>
<hr>
<div class="spirit-nav"><a accesskey="n" href="python/hello.html"><img src="images/next.png" alt="Next"></a></div>
<div class="chapter" lang="en">
<div class="titlepage">
<div>
<div><h2 class="title">
<a name="python"></a>Chapter 1. python 1.0</h2></div>
<div><div class="author"><h3 class="author">
<span class="firstname">Joel</span> <span class="surname">de Guzman</span>
</h3></div></div>
<div><div class="author"><h3 class="author">
<span class="firstname">David</span> <span class="surname">Abrahams</span>
</h3></div></div>
<div><p class="copyright">Copyright © 2002-2004 Joel de Guzman, David Abrahams</p></div>
<div><div class="legalnotice"><p>
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
<a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">
http://www.boost.org/LICENSE_1_0.txt
</a>)
</p></div></div>
</div>
<div></div>
</div>
<div class="toc">
<p><b>Table of Contents</b></p>
<dl>
<dt><span class="section"><a href="index.html#python.quickstart">QuickStart</a></span></dt>
<dt><span class="section"><a href="python/hello.html"> Building Hello World</a></span></dt>
<dt><span class="section"><a href="python/exposing.html"> Exposing Classes</a></span></dt>
<dd><dl>
<dt><span class="section"><a href="python/exposing.html#python.constructors">Constructors</a></span></dt>
<dt><span class="section"><a href="python/exposing.html#python.class_data_members">Class Data Members</a></span></dt>
<dt><span class="section"><a href="python/exposing.html#python.class_properties">Class Properties</a></span></dt>
<dt><span class="section"><a href="python/exposing.html#python.inheritance">Inheritance</a></span></dt>
<dt><span class="section"><a href="python/exposing.html#python.class_virtual_functions">Class Virtual Functions</a></span></dt>
<dt><span class="section"><a href="python/exposing.html#python.deriving_a_python_class">Deriving a Python Class</a></span></dt>
<dt><span class="section"><a href="python/exposing.html#python.virtual_functions_with_default_implementations">Virtual Functions with Default Implementations</a></span></dt>
<dt><span class="section"><a href="python/exposing.html#python.class_operators_special_functions">Class Operators/Special Functions</a></span></dt>
</dl></dd>
<dt><span class="section"><a href="python/functions.html">Functions</a></span></dt>
<dd><dl>
<dt><span class="section"><a href="python/functions.html#python.call_policies">Call Policies</a></span></dt>
<dt><span class="section"><a href="python/functions.html#python.overloading">Overloading</a></span></dt>
<dt><span class="section"><a href="python/functions.html#python.default_arguments">Default Arguments</a></span></dt>
<dt><span class="section"><a href="python/functions.html#python.auto_overloading">Auto-Overloading</a></span></dt>
</dl></dd>
<dt><span class="section"><a href="python/object.html"> Object Interface</a></span></dt>
<dd><dl>
<dt><span class="section"><a href="python/object.html#python.basic_interface">Basic Interface</a></span></dt>
<dt><span class="section"><a href="python/object.html#python.derived_object_types">Derived Object types</a></span></dt>
<dt><span class="section"><a href="python/object.html#python.extracting_c___objects">Extracting C++ objects</a></span></dt>
<dt><span class="section"><a href="python/object.html#python.enums">Enums</a></span></dt>
</dl></dd>
<dt><span class="section"><a href="python/embedding.html">Embedding</a></span></dt>
<dd><dl><dt><span class="section"><a href="python/embedding.html#python.using_the_interpreter">Using the interpreter</a></span></dt></dl></dd>
<dt><span class="section"><a href="python/iterators.html">Iterators</a></span></dt>
<dt><span class="section"><a href="python/exception.html"> Exception Translation</a></span></dt>
<dt><span class="section"><a href="python/techniques.html"> General Techniques</a></span></dt>
<dd><dl>
<dt><span class="section"><a href="python/techniques.html#python.creating_packages">Creating Packages</a></span></dt>
<dt><span class="section"><a href="python/techniques.html#python.extending_wrapped_objects_in_python">Extending Wrapped Objects in Python</a></span></dt>
<dt><span class="section"><a href="python/techniques.html#python.reducing_compiling_time">Reducing Compiling Time</a></span></dt>
</dl></dd>
</dl>
</div>
<div class="section" lang="en">
<div class="titlepage">
<div><div><h2 class="title" style="clear: both">
<a name="python.quickstart"></a>QuickStart</h2></div></div>
<div></div>
</div>
<p>
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
@@ -11,20 +99,39 @@ 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).</p><a name="quickstart.hello_world"></a><h2><a name="id343260"></a>Hello World</h2><p>
definition language (IDL).</p>
<a name="quickstart.hello_world"></a><h2>
<a name="id344076"></a>Hello World</h2>
<p>
Following C/C++ tradition, let's start with the "hello, world". A C++
Function:</p><pre class="programlisting"><tt class="literal"><span class="keyword"> char</span><span class="keyword"> const</span><span class="special">*</span><span class="identifier"> greet</span><span class="special">()</span><span class="special">
{</span><span class="keyword">
return</span><span class="string"> "hello, world"</span><span class="special">;</span><span class="special">
}</span></tt></pre><p>
can be exposed to Python by writing a Boost.Python wrapper:</p><pre class="programlisting"><tt class="literal"><span class="preprocessor"> #include</span><span class="special"> &lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">python</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span><span class="keyword">
using</span><span class="keyword"> namespace</span><span class="identifier"> boost</span><span class="special">::</span><span class="identifier">python</span><span class="special">;</span><span class="identifier">
Function:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">char</span><span class="keyword"> const</span><span class="special">*</span><span class="identifier"> greet</span><span class="special">()</span><span class="special">
{</span><span class="keyword">
return</span><span class="string"> "hello, world"</span><span class="special">;</span><span class="special">
}</span></tt></pre>
<p>
can be exposed to Python by writing a Boost.Python wrapper:</p>
<pre class="programlisting"><tt class="literal"><span class="preprocessor">#include</span><span class="special"> &lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">python</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span><span class="keyword">
using</span><span class="keyword"> namespace</span><span class="identifier"> boost</span><span class="special">::</span><span class="identifier">python</span><span class="special">;</span><span class="identifier">
BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">hello</span><span class="special">)</span><span class="special">
{</span><span class="identifier">
def</span><span class="special">(</span><span class="string">"greet"</span><span class="special">,</span><span class="identifier"> greet</span><span class="special">);</span><span class="special">
}</span></tt></pre><p>
BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">hello</span><span class="special">)</span><span class="special">
{</span><span class="identifier">
def</span><span class="special">(</span><span class="string">"greet"</span><span class="special">,</span><span class="identifier"> greet</span><span class="special">);</span><span class="special">
}</span></tt></pre>
<p>
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:</p><pre class="programlisting"><tt class="literal"><span class="special"> &gt;&gt;&gt;</span><span class="identifier"> import</span><span class="identifier"> hello</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> print</span><span class="identifier"> hello</span><span class="special">.</span><span class="identifier">greet</span><span class="special">()</span><span class="identifier">
hello</span><span class="special">,</span><span class="identifier"> world</span></tt></pre><div class="blockquote"><blockquote class="blockquote"><p><span class="emphasis"><em><span class="bold"><b>Next stop... Building your Hello World module from start to finish...</b></span></em></span></p></blockquote></div></div></div><table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr><td align="left"><small><p>Last revised: September 16, 2004 at 03:53:11 GMT</p></small></td><td align="right"><small></small></td></tr></table><hr><div class="spirit-nav"><a accesskey="n" href="boost_python.hello.html"><img src="images/next.png" alt="Next"></a></div></body></html>
resulting DLL is now visible to Python. Here's a sample Python session:</p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="identifier"> import</span><span class="identifier"> hello</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> print</span><span class="identifier"> hello</span><span class="special">.</span><span class="identifier">greet</span><span class="special">()</span><span class="identifier">
hello</span><span class="special">,</span><span class="identifier"> world</span></tt></pre>
<div class="blockquote"><blockquote class="blockquote"><p><span class="emphasis"><em><span class="bold"><b>Next stop... Building your Hello World module from start to finish...</b></span></em></span></p></blockquote></div>
</div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"><small><p>Last revised: October 12, 2004 at 03:11:11 GMT</p></small></td>
<td align="right"><small></small></td>
</tr></table>
<hr>
<div class="spirit-nav"><a accesskey="n" href="python/hello.html"><img src="images/next.png" alt="Next"></a></div>
</body>
</html>

View File

@@ -0,0 +1,347 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Embedding</title>
<link rel="stylesheet" href="../boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.65.1">
<link rel="home" href="../index.html" title="Chapter 1. python 1.0">
<link rel="up" href="../index.html" title="Chapter 1. python 1.0">
<link rel="previous" href="object.html" title=" Object Interface">
<link rel="next" href="iterators.html" title="Iterators">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%">
<td valign="top"><img alt="boost.png (6897 bytes)" width="277" height="86" src="../../../boost.png"></td>
<td align="center"><a href="../../../index.htm">Home</a></td>
<td align="center"><a href="../libraries.html">Libraries</a></td>
<td align="center"><a href="../../../people/people.htm">People</a></td>
<td align="center"><a href="../../../more/faq.htm">FAQ</a></td>
<td align="center"><a href="../../../more/index.htm">More</a></td>
</table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="object.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="iterators.html"><img src="../images/next.png" alt="Next"></a>
</div>
<div class="section" lang="en">
<div class="titlepage">
<div><div><h2 class="title" style="clear: both">
<a name="python.embedding"></a>Embedding</h2></div></div>
<div></div>
</div>
<div class="toc"><dl><dt><span class="section"><a href="embedding.html#python.using_the_interpreter">Using the interpreter</a></span></dt></dl></div>
<p>
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 <span class="emphasis"><em>embed</em></span> the Python interpreter
into your C++ program.</p>
<p>
Currently, Boost.Python does not directly support everything you'll need
when embedding. Therefore you'll need to use the
<a href="http://www.python.org/doc/current/api/api.html" target="_top">Python/C API</a> 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... <span class="inlinemediaobject"><img src="../images/smiley.png"></span></p>
<a name="embedding.building_embedded_programs"></a><h2>
<a name="id428755"></a>Building embedded programs</h2>
<p>
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.</p>
<p>
Boost.Python's static link library comes in two variants. Both are located
in Boost's <tt class="literal">/libs/python/build/bin-stage</tt> subdirectory. On Windows, the
variants are called <tt class="literal">boost_python.lib</tt> (for release builds) and
<tt class="literal">boost_python_debug.lib</tt> (for debugging). If you can't find the libraries,
you probably haven't built Boost.Python yet. See <a href="../../../../building.html%20Building" target="_top">and Testing</a> on how to do this.</p>
<p>
Python's static link library can be found in the <tt class="literal">/libs</tt> subdirectory of
your Python directory. On Windows it is called pythonXY.lib where X.Y is
your major Python version number.</p>
<p>
Additionally, Python's <tt class="literal">/include</tt> subdirectory has to be added to your
include path.</p>
<p>
In a Jamfile, all the above boils down to:</p>
<pre class="programlisting"><tt class="literal"> 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
&lt;find-library&gt;boost_python &lt;library-path&gt;c:\boost\libs\python
$(PYTHON_PROPERTIES)
&lt;library-path&gt;$(PYTHON_LIB_PATH)
&lt;find-library&gt;$(PYTHON_EMBEDDED_LIBRARY) ;
</tt></pre>
<a name="embedding.getting_started"></a><h2>
<a name="id428846"></a>Getting started</h2>
<p>
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:</p>
<div class="orderedlist"><ol type="1">
<li>
#include <tt class="literal">&lt;boost/python.hpp&gt;</tt><p></p>
<p></p>
</li>
<li>
Call <a href="http://www.python.org/doc/current/api/initialization.html#l2h-652" target="_top">Py_Initialize</a>() to start the interpreter and create the <tt class="literal"><span class="underline">_main</span>_</tt> module.<p></p>
<p></p>
</li>
<li>
Call other Python C API routines to use the interpreter.<p></p>
<p></p>
</li>
<li>
Call <a href="http://www.python.org/doc/current/api/initialization.html#l2h-656" target="_top">Py_Finalize</a>() to stop the interpreter and release its resources.
</li>
</ol></div>
<p>
(Of course, there can be other C++ code between all of these steps.)</p>
<div class="blockquote"><blockquote class="blockquote"><p><span class="emphasis"><em><span class="bold"><b>Now that we can embed the interpreter in our programs, lets see how to put it to use...</b></span></em></span></p></blockquote></div>
<div class="section" lang="en">
<div class="titlepage">
<div><div><h3 class="title">
<a name="python.using_the_interpreter"></a>Using the interpreter</h3></div></div>
<div></div>
</div>
<p>
As you probably already know, objects in Python are reference-counted.
Naturally, the <tt class="literal">PyObject</tt>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
<a href="http://www.python.org/doc/current/api/refcounts.html" target="_top">by hand</a>. This is
messy and especially hard to get right in the presence of C++ exceptions.
Fortunately Boost.Python provides the <a href="../../v2/handle.html" target="_top">handle</a> and
<a href="../../../../v2/object.html" target="_top">object</a> class templates to automate the process.</p>
<a name="using_the_interpreter.reference_counting_handles_and_objects"></a><h2>
<a name="id428977"></a>Reference-counting handles and objects</h2>
<p>
There are two ways in which a function in the Python/C API can return a
<tt class="literal">PyObject*</tt>: as a <span class="emphasis"><em>borrowed reference</em></span> or as a <span class="emphasis"><em>new reference</em></span>. 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.</p>
<p>
For a function returning a <span class="emphasis"><em>borrowed reference</em></span> we'll have to tell the
<tt class="literal">handle</tt> that the <tt class="literal">PyObject*</tt> is borrowed with the aptly named
<a href="../../../../v2/handle.html#borrowed-spec" target="_top">borrowed</a> function. Two functions
returning borrowed references are <a href="http://www.python.org/doc/current/api/importing.html#l2h-125" target="_top">PyImport_AddModule</a> and <a href="http://www.python.org/doc/current/api/moduleObjects.html#l2h-594" target="_top">PyModule_GetDict</a>.
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 <tt class="literal"><span class="underline">_main</span>_</tt> module:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">object</span><span class="identifier"> main_module</span><span class="special">((</span><span class="identifier">
handle</span><span class="special">&lt;&gt;(</span><span class="identifier">borrowed</span><span class="special">(</span><a href="http://www.python.org/doc/current/api/importing.html#l2h-125" target="_top">PyImport_AddModule</a><span class="special">(</span><span class="string">"__main__"</span><span class="special">)))));</span><span class="identifier">
object</span><span class="identifier"> main_namespace</span><span class="special"> =</span><span class="identifier"> main_module</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"__dict__"</span><span class="special">);</span></tt></pre>
<p>
For a function returning a <span class="emphasis"><em>new reference</em></span> we can just create a <tt class="literal">handle</tt>
out of the raw <tt class="literal">PyObject*</tt> without wrapping it in a call to borrowed. One
such function that returns a new reference is <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55" target="_top">PyRun_String</a> which we'll
discuss in the next section.</p>
<div class="informaltable"><table class="table">
<colgroup><col></colgroup>
<tbody><tr><td>
<span class="inlinemediaobject"><img src="../images/note.png"></span><span class="bold"><b>Handle is a class <span class="emphasis"><em>template</em></span>, so why haven't we been using any template parameters?</b></span><p></p>
<p></p>
<tt class="literal">handle</tt> has a single template parameter specifying the type of the managed object. This type is <tt class="literal">PyObject</tt> 99% of the time, so the parameter was defaulted to <tt class="literal">PyObject</tt> for convenience. Therefore we can use the shorthand <tt class="literal">handle&lt;&gt;</tt> instead of the longer, but equivalent, <tt class="literal">handle&lt;PyObject&gt;</tt>.
</td></tr></tbody>
</table></div>
<a name="using_the_interpreter.running_python_code"></a><h2>
<a name="id429281"></a>Running Python code</h2>
<p>
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 <a href="http://www.python.org/doc/current/api/veryhigh.html" target="_top">here</a>. They
all work similarly so we will look at only one of them, namely:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">PyObject</span><span class="special">*</span> <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55" target="_top">PyRun_String</a><span class="special">(</span><span class="keyword">char</span><span class="special"> *</span><span class="identifier">str</span><span class="special">,</span><span class="keyword"> int</span><span class="identifier"> start</span><span class="special">,</span><span class="identifier"> PyObject</span><span class="special"> *</span><span class="identifier">globals</span><span class="special">,</span><span class="identifier"> PyObject</span><span class="special"> *</span><span class="identifier">locals</span><span class="special">)</span></tt></pre>
<p><a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55" target="_top">PyRun_String</a> takes the code to execute as a null-terminated (C-style)
string in its <tt class="literal">str</tt> parameter. The function returns a new reference to a
Python object. Which object is returned depends on the <tt class="literal">start</tt> paramater.</p>
<p>
The <tt class="literal">start</tt> parameter is the start symbol from the Python grammar to use
for interpreting the code. The possible values are:</p>
<div class="informaltable">
<h4>
<a name="id429442"></a><span class="table-title">Start symbols</span>
</h4>
<table class="table">
<colgroup>
<col>
<col>
</colgroup>
<thead><tr>
<th><a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-58" target="_top">Py_eval_input</a></th>
<th>for interpreting isolated expressions</th>
</tr></thead>
<tbody>
<tr>
<td><a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-59" target="_top">Py_file_input</a></td>
<td>for interpreting sequences of statements</td>
</tr>
<tr>
<td><a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-60" target="_top">Py_single_input</a></td>
<td>for interpreting a single statement</td>
</tr>
</tbody>
</table>
</div>
<p>
When using <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-58" target="_top">Py_eval_input</a>, the input string must contain a single expression
and its result is returned. When using <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-59" target="_top">Py_file_input</a>, the string can
contain an abitrary number of statements and None is returned.
<a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-60" target="_top">Py_single_input</a> works in the same way as <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-59" target="_top">Py_file_input</a> but only accepts a
single statement.</p>
<p>
Lastly, the <tt class="literal">globals</tt> and <tt class="literal">locals</tt> 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
<tt class="literal"><span class="underline">_main</span>_</tt> module for both parameters.</p>
<p>
We have already seen how to get the <tt class="literal"><span class="underline">_main</span>_</tt> module's namespace so let's
run some Python code in it:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">object</span><span class="identifier"> main_module</span><span class="special">((</span><span class="identifier">
handle</span><span class="special">&lt;&gt;(</span><span class="identifier">borrowed</span><span class="special">(</span><a href="http://www.python.org/doc/current/api/importing.html#l2h-125" target="_top">PyImport_AddModule</a><span class="special">(</span><span class="string">"__main__"</span><span class="special">)))));</span><span class="identifier">
object</span><span class="identifier"> main_namespace</span><span class="special"> =</span><span class="identifier"> main_module</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"__dict__"</span><span class="special">);</span><span class="identifier">
handle</span><span class="special">&lt;&gt;</span><span class="identifier"> ignored</span><span class="special">((</span><a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55" target="_top">PyRun_String</a><span class="special">(</span><span class="string">
"hello = file('hello.txt', 'w')\n"</span><span class="string">
"hello.write('Hello world!')\n"</span><span class="string">
"hello.close()"</span><span class="special">
,</span> <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-59" target="_top">Py_file_input</a><span class="special">
,</span><span class="identifier"> main_namespace</span><span class="special">.</span><span class="identifier">ptr</span><span class="special">()</span><span class="special">
,</span><span class="identifier"> main_namespace</span><span class="special">.</span><span class="identifier">ptr</span><span class="special">())</span><span class="special">
));</span></tt></pre>
<p>
Because the Python/C API doesn't know anything about <tt class="literal">object</tt>s, we used
the object's <tt class="literal">ptr</tt> member function to retrieve the <tt class="literal">PyObject*</tt>.</p>
<p>
This should create a file called 'hello.txt' in the current directory
containing a phrase that is well-known in programming circles.</p>
<p><span class="inlinemediaobject"><img src="../images/note.png"></span><span class="bold"><b>Note</b></span> that we wrap the return value of <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55" target="_top">PyRun_String</a> in a
(nameless) <tt class="literal">handle</tt> 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 <tt class="literal">PyObject*</tt>s in <tt class="literal">handle</tt>s.</p>
<a name="using_the_interpreter.beyond_handles"></a><h2>
<a name="id429881"></a>Beyond handles</h2>
<p>
It's nice that <tt class="literal">handle</tt> 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 <a href="object.html" target="_top">previous section</a>: the aptly
named <tt class="literal">object</tt> class and it's derivatives. We've already seen that they
can be constructed from a <tt class="literal">handle</tt>. The following examples should further
illustrate this fact:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">object</span><span class="identifier"> main_module</span><span class="special">((</span><span class="identifier">
handle</span><span class="special">&lt;&gt;(</span><span class="identifier">borrowed</span><span class="special">(</span><a href="http://www.python.org/doc/current/api/importing.html#l2h-125" target="_top">PyImport_AddModule</a><span class="special">(</span><span class="string">"__main__"</span><span class="special">)))));</span><span class="identifier">
object</span><span class="identifier"> main_namespace</span><span class="special"> =</span><span class="identifier"> main_module</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"__dict__"</span><span class="special">);</span><span class="identifier">
handle</span><span class="special">&lt;&gt;</span><span class="identifier"> ignored</span><span class="special">((</span><a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55" target="_top">PyRun_String</a><span class="special">(</span><span class="string">
"result = 5 ** 2"</span><span class="special">
,</span> <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-59" target="_top">Py_file_input</a><span class="special">
,</span><span class="identifier"> main_namespace</span><span class="special">.</span><span class="identifier">ptr</span><span class="special">()</span><span class="special">
,</span><span class="identifier"> main_namespace</span><span class="special">.</span><span class="identifier">ptr</span><span class="special">())</span><span class="special">
));</span><span class="keyword">
int</span><span class="identifier"> five_squared</span><span class="special"> =</span><span class="identifier"> extract</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;(</span><span class="identifier">main_namespace</span><span class="special">[</span><span class="string">"result"</span><span class="special">]);</span></tt></pre>
<p>
Here we create a dictionary object for the <tt class="literal"><span class="underline">_main</span>_</tt> 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
<a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55" target="_top">PyRun_String</a> return the result directly with <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-58" target="_top">Py_eval_input</a>:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">object</span><span class="identifier"> result</span><span class="special">((</span><span class="identifier">handle</span><span class="special">&lt;&gt;(</span>
    <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55" target="_top">PyRun_String</a><span class="special">(</span><span class="string">"5 ** 2"</span><span class="special">
,</span> <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-58" target="_top">Py_eval_input</a><span class="special">
,</span><span class="identifier"> main_namespace</span><span class="special">.</span><span class="identifier">ptr</span><span class="special">()</span><span class="special">
,</span><span class="identifier"> main_namespace</span><span class="special">.</span><span class="identifier">ptr</span><span class="special">()))</span><span class="special">
));</span><span class="keyword">
int</span><span class="identifier"> five_squared</span><span class="special"> =</span><span class="identifier"> extract</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;(</span><span class="identifier">result</span><span class="special">);</span></tt></pre>
<p><span class="inlinemediaobject"><img src="../images/note.png"></span><span class="bold"><b>Note</b></span> that <tt class="literal">object</tt>'s member function to return the wrapped
<tt class="literal">PyObject*</tt> is called <tt class="literal">ptr</tt> instead of <tt class="literal">get</tt>. This makes sense if you
take into account the different functions that <tt class="literal">object</tt> and <tt class="literal">handle</tt>
perform.</p>
<a name="using_the_interpreter.exception_handling"></a><h2>
<a name="id430451"></a>Exception handling</h2>
<p>
If an exception occurs in the execution of some Python code, the <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55" target="_top">PyRun_String</a>
function returns a null pointer. Constructing a <tt class="literal">handle</tt> out of this null
pointer throws <a href="../../../../v2/errors.html#error_already_set-spec" target="_top">error_already_set</a>,
so basically, the Python exception is automatically translated into a
C++ exception when using <tt class="literal">handle</tt>:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">try</span><span class="special">
{</span><span class="identifier">
object</span><span class="identifier"> result</span><span class="special">((</span><span class="identifier">handle</span><span class="special">&lt;&gt;(</span><a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55" target="_top">PyRun_String</a><span class="special">(</span><span class="string">
"5/0"</span><span class="special">
,</span> <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-58" target="_top">Py_eval_input</a><span class="special">
,</span><span class="identifier"> main_namespace</span><span class="special">.</span><span class="identifier">ptr</span><span class="special">()</span><span class="special">
,</span><span class="identifier"> main_namespace</span><span class="special">.</span><span class="identifier">ptr</span><span class="special">()))</span><span class="special">
));</span><span class="comment">
// execution will never get here:
</span><span class="keyword"> int</span><span class="identifier"> five_divided_by_zero</span><span class="special"> =</span><span class="identifier"> extract</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;(</span><span class="identifier">result</span><span class="special">);</span><span class="special">
}</span><span class="keyword">
catch</span><span class="special">(</span><span class="identifier">error_already_set</span><span class="special">)</span><span class="special">
{</span><span class="comment">
// handle the exception in some way
</span><span class="special">}</span></tt></pre>
<p>
The <tt class="literal">error_already_set</tt> exception class doesn't carry any information in itself.
To find out more about the Python exception that occurred, you need to use the
<a href="http://www.python.org/doc/api/exceptionHandling.html" target="_top">exception handling functions</a>
of the Python/C API in your catch-statement. This can be as simple as calling
<a href="http://www.python.org/doc/api/exceptionHandling.html#l2h-70" target="_top">PyErr_Print()</a> to
print the exception's traceback to the console, or comparing the type of the
exception with those of the <a href="http://www.python.org/doc/api/standardExceptions.html" target="_top">
standard exceptions</a>:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">catch</span><span class="special">(</span><span class="identifier">error_already_set</span><span class="special">)</span><span class="special">
{</span><span class="keyword">
if</span><span class="special"> (</span><span class="identifier">PyErr_ExceptionMatches</span><span class="special">(</span><span class="identifier">PyExc_ZeroDivisionError</span><span class="special">))</span><span class="special">
{</span><span class="comment">
// handle ZeroDivisionError specially
</span><span class="special"> }</span><span class="keyword">
else</span><span class="special">
{</span><span class="comment">
// print all other errors to stderr
</span><span class="identifier"> PyErr_Print</span><span class="special">();</span><span class="special">
}</span><span class="special">
}</span></tt></pre>
<p>
(To retrieve even more information from the exception you can use some of the other
exception handling functions listed <a href="http://www.python.org/doc/api/exceptionHandling.html" target="_top">here</a>.)</p>
<p>
If you'd rather not have <tt class="literal">handle</tt> throw a C++ exception when it is constructed, you
can use the <a href="../../v2/handle.html#allow_null-spec" target="_top">allow_null</a> function in the same
way you'd use borrowed:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">handle</span><span class="special">&lt;&gt;</span><span class="identifier"> result</span><span class="special">((</span><span class="identifier">allow_null</span><span class="special">(</span><a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-55" target="_top">PyRun_String</a><span class="special">(</span><span class="string">
"5/0"</span><span class="special">
,</span> <a href="http://www.python.org/doc/current/api/veryhigh.html#l2h-58" target="_top">Py_eval_input</a><span class="special">
,</span><span class="identifier"> main_namespace</span><span class="special">.</span><span class="identifier">ptr</span><span class="special">()</span><span class="special">
,</span><span class="identifier"> main_namespace</span><span class="special">.</span><span class="identifier">ptr</span><span class="special">()))));</span><span class="keyword">
if</span><span class="special"> (!</span><span class="identifier">result</span><span class="special">)</span><span class="comment">
// Python exception occurred
</span><span class="keyword">else</span><span class="comment">
// everything went okay, it's safe to use the result
</span></tt></pre>
</div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><small>Copyright © 2002-2004 Joel de Guzman, David Abrahams</small></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="object.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="iterators.html"><img src="../images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -0,0 +1,57 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title> Exception Translation</title>
<link rel="stylesheet" href="../boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.65.1">
<link rel="home" href="../index.html" title="Chapter 1. python 1.0">
<link rel="up" href="../index.html" title="Chapter 1. python 1.0">
<link rel="previous" href="iterators.html" title="Iterators">
<link rel="next" href="techniques.html" title=" General Techniques">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%">
<td valign="top"><img alt="boost.png (6897 bytes)" width="277" height="86" src="../../../boost.png"></td>
<td align="center"><a href="../../../index.htm">Home</a></td>
<td align="center"><a href="../libraries.html">Libraries</a></td>
<td align="center"><a href="../../../people/people.htm">People</a></td>
<td align="center"><a href="../../../more/faq.htm">FAQ</a></td>
<td align="center"><a href="../../../more/index.htm">More</a></td>
</table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="iterators.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="techniques.html"><img src="../images/next.png" alt="Next"></a>
</div>
<div class="section" lang="en">
<div class="titlepage">
<div><div><h2 class="title" style="clear: both">
<a name="python.exception"></a> Exception Translation</h2></div></div>
<div></div>
</div>
<p>
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:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">raise</span><span class="identifier"> RuntimeError</span><span class="special">,</span><span class="char"> 'unidentifiable C++ Exception'</span></tt></pre>
<p>
Users may provide custom translation. Here's an example:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">struct</span><span class="identifier"> PodBayDoorException</span><span class="special">;</span><span class="keyword">
void</span><span class="identifier"> translator</span><span class="special">(</span><span class="identifier">PodBayDoorException</span><span class="keyword"> const</span><span class="special">&amp;</span><span class="identifier"> x</span><span class="special">)</span><span class="special"> {</span><span class="identifier">
PyErr_SetString</span><span class="special">(</span><span class="identifier">PyExc_UserWarning</span><span class="special">,</span><span class="string"> "I'm sorry Dave..."</span><span class="special">);</span><span class="special">
}</span><span class="identifier">
BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">kubrick</span><span class="special">)</span><span class="special"> {</span><span class="identifier">
register_exception_translator</span><span class="special">&lt;</span><span class="identifier">
PodBayDoorException</span><span class="special">&gt;(</span><span class="identifier">translator</span><span class="special">);</span><span class="special">
...</span></tt></pre>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><small>Copyright © 2002-2004 Joel de Guzman, David Abrahams</small></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="iterators.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="techniques.html"><img src="../images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -0,0 +1,580 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title> Exposing Classes</title>
<link rel="stylesheet" href="../boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.65.1">
<link rel="home" href="../index.html" title="Chapter 1. python 1.0">
<link rel="up" href="../index.html" title="Chapter 1. python 1.0">
<link rel="previous" href="hello.html" title=" Building Hello World">
<link rel="next" href="functions.html" title="Functions">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%">
<td valign="top"><img alt="boost.png (6897 bytes)" width="277" height="86" src="../../../boost.png"></td>
<td align="center"><a href="../../../index.htm">Home</a></td>
<td align="center"><a href="../libraries.html">Libraries</a></td>
<td align="center"><a href="../../../people/people.htm">People</a></td>
<td align="center"><a href="../../../more/faq.htm">FAQ</a></td>
<td align="center"><a href="../../../more/index.htm">More</a></td>
</table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="hello.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="functions.html"><img src="../images/next.png" alt="Next"></a>
</div>
<div class="section" lang="en">
<div class="titlepage">
<div><div><h2 class="title" style="clear: both">
<a name="python.exposing"></a> Exposing Classes</h2></div></div>
<div></div>
</div>
<div class="toc"><dl>
<dt><span class="section"><a href="exposing.html#python.constructors">Constructors</a></span></dt>
<dt><span class="section"><a href="exposing.html#python.class_data_members">Class Data Members</a></span></dt>
<dt><span class="section"><a href="exposing.html#python.class_properties">Class Properties</a></span></dt>
<dt><span class="section"><a href="exposing.html#python.inheritance">Inheritance</a></span></dt>
<dt><span class="section"><a href="exposing.html#python.class_virtual_functions">Class Virtual Functions</a></span></dt>
<dt><span class="section"><a href="exposing.html#python.deriving_a_python_class">Deriving a Python Class</a></span></dt>
<dt><span class="section"><a href="exposing.html#python.virtual_functions_with_default_implementations">Virtual Functions with Default Implementations</a></span></dt>
<dt><span class="section"><a href="exposing.html#python.class_operators_special_functions">Class Operators/Special Functions</a></span></dt>
</dl></div>
<p>
Now let's expose a C++ class to Python.</p>
<p>
Consider a C++ class/struct that we want to expose to Python:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">struct</span><span class="identifier"> World</span><span class="special">
{</span><span class="keyword">
void</span><span class="identifier"> set</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="identifier"> msg</span><span class="special">)</span><span class="special"> {</span><span class="keyword"> this</span><span class="special">-&gt;</span><span class="identifier">msg</span><span class="special"> =</span><span class="identifier"> msg</span><span class="special">;</span><span class="special"> }</span><span class="identifier">
std</span><span class="special">::</span><span class="identifier">string</span><span class="identifier"> greet</span><span class="special">()</span><span class="special"> {</span><span class="keyword"> return</span><span class="identifier"> msg</span><span class="special">;</span><span class="special"> }</span><span class="identifier">
std</span><span class="special">::</span><span class="identifier">string</span><span class="identifier"> msg</span><span class="special">;</span><span class="special">
};</span></tt></pre>
<p>
We can expose this to Python by writing a corresponding Boost.Python
C++ Wrapper:</p>
<pre class="programlisting"><tt class="literal"><span class="preprocessor">#include</span><span class="special"> &lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">python</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span><span class="keyword">
using</span><span class="keyword"> namespace</span><span class="identifier"> boost</span><span class="special">::</span><span class="identifier">python</span><span class="special">;</span><span class="identifier">
BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">hello</span><span class="special">)</span><span class="special">
{</span><span class="identifier">
class_</span><span class="special">&lt;</span><span class="identifier">World</span><span class="special">&gt;(</span><span class="string">"World"</span><span class="special">)</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"greet"</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">World</span><span class="special">::</span><span class="identifier">greet</span><span class="special">)</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"set"</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">World</span><span class="special">::</span><span class="identifier">set</span><span class="special">)</span><span class="special">
;</span><span class="special">
}</span></tt></pre>
<p>
Here, we wrote a C++ class wrapper that exposes the member functions
<tt class="literal">greet</tt> and <tt class="literal">set</tt>. Now, after building our module as a shared library, we
may use our class <tt class="literal">World</tt> in Python. Here's a sample Python session:</p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="identifier"> import</span><span class="identifier"> hello</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> planet</span><span class="special"> =</span><span class="identifier"> hello</span><span class="special">.</span><span class="identifier">World</span><span class="special">()</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> planet</span><span class="special">.</span><span class="identifier">set</span><span class="special">(</span><span class="char">'howdy'</span><span class="special">)</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> planet</span><span class="special">.</span><span class="identifier">greet</span><span class="special">()</span><span class="char">
'howdy'</span></tt></pre>
<div class="section" lang="en">
<div class="titlepage">
<div><div><h3 class="title">
<a name="python.constructors"></a>Constructors</h3></div></div>
<div></div>
</div>
<p>
Our previous example didn't have any explicit constructors.
Since <tt class="literal">World</tt> 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</p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="identifier"> planet</span><span class="special"> =</span><span class="identifier"> hello</span><span class="special">.</span><span class="identifier">World</span><span class="special">()</span></tt></pre>
<p>
We may wish to wrap a class with a non-default constructor. Let us
build on our previous example:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">struct</span><span class="identifier"> World</span><span class="special">
{</span><span class="identifier">
World</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="identifier"> msg</span><span class="special">):</span><span class="identifier"> msg</span><span class="special">(</span><span class="identifier">msg</span><span class="special">)</span><span class="special"> {}</span><span class="comment"> // added constructor
</span><span class="keyword"> void</span><span class="identifier"> set</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="identifier"> msg</span><span class="special">)</span><span class="special"> {</span><span class="keyword"> this</span><span class="special">-&gt;</span><span class="identifier">msg</span><span class="special"> =</span><span class="identifier"> msg</span><span class="special">;</span><span class="special"> }</span><span class="identifier">
std</span><span class="special">::</span><span class="identifier">string</span><span class="identifier"> greet</span><span class="special">()</span><span class="special"> {</span><span class="keyword"> return</span><span class="identifier"> msg</span><span class="special">;</span><span class="special"> }</span><span class="identifier">
std</span><span class="special">::</span><span class="identifier">string</span><span class="identifier"> msg</span><span class="special">;</span><span class="special">
};</span></tt></pre>
<p>
This time <tt class="literal">World</tt> has no default constructor; our previous
wrapping code would fail to compile when the library tried to expose
it. We have to tell <tt class="literal">class_&lt;World&gt;</tt> about the constructor we want to
expose instead.</p>
<pre class="programlisting"><tt class="literal"><span class="preprocessor">#include</span><span class="special"> &lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">python</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span><span class="keyword">
using</span><span class="keyword"> namespace</span><span class="identifier"> boost</span><span class="special">::</span><span class="identifier">python</span><span class="special">;</span><span class="identifier">
BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">hello</span><span class="special">)</span><span class="special">
{</span><span class="identifier">
class_</span><span class="special">&lt;</span><span class="identifier">World</span><span class="special">&gt;(</span><span class="string">"World"</span><span class="special">,</span><span class="identifier"> init</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&gt;())</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"greet"</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">World</span><span class="special">::</span><span class="identifier">greet</span><span class="special">)</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"set"</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">World</span><span class="special">::</span><span class="identifier">set</span><span class="special">)</span><span class="special">
;</span><span class="special">
}</span></tt></pre>
<p><tt class="literal">init&lt;std::string&gt;()</tt> exposes the constructor taking in a
<tt class="literal">std::string</tt> (in Python, constructors are spelled
"<tt class="literal">"<span class="underline">_init</span>_"</tt>").</p>
<p>
We can expose additional constructors by passing more <tt class="literal">init&lt;...&gt;</tt>s to
the <tt class="literal">def()</tt> member function. Say for example we have another World
constructor taking in two doubles:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">class_</span><span class="special">&lt;</span><span class="identifier">World</span><span class="special">&gt;(</span><span class="string">"World"</span><span class="special">,</span><span class="identifier"> init</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&gt;())</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">init</span><span class="special">&lt;</span><span class="keyword">double</span><span class="special">,</span><span class="keyword"> double</span><span class="special">&gt;())</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"greet"</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">World</span><span class="special">::</span><span class="identifier">greet</span><span class="special">)</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"set"</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">World</span><span class="special">::</span><span class="identifier">set</span><span class="special">)</span><span class="special">
;</span></tt></pre>
<p>
On the other hand, if we do not wish to expose any constructors at
all, we may use <tt class="literal">no_init</tt> instead:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">class_</span><span class="special">&lt;</span><span class="identifier">Abstract</span><span class="special">&gt;(</span><span class="string">"Abstract"</span><span class="special">,</span><span class="identifier"> no_init</span><span class="special">)</span></tt></pre>
<p>
This actually adds an <tt class="literal"><span class="underline">_init</span>_</tt> method which always raises a
Python RuntimeError exception.</p>
</div>
<div class="section" lang="en">
<div class="titlepage">
<div><div><h3 class="title">
<a name="python.class_data_members"></a>Class Data Members</h3></div></div>
<div></div>
</div>
<p>
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 <span class="bold"><b>read-only</b></span> or
<span class="bold"><b>read-write</b></span>. Consider this class <tt class="literal">Var</tt>:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">struct</span><span class="identifier"> Var</span><span class="special">
{</span><span class="identifier">
Var</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="identifier"> name</span><span class="special">)</span><span class="special"> :</span><span class="identifier"> name</span><span class="special">(</span><span class="identifier">name</span><span class="special">),</span><span class="identifier"> value</span><span class="special">()</span><span class="special"> {}</span><span class="identifier">
std</span><span class="special">::</span><span class="identifier">string</span><span class="keyword"> const</span><span class="identifier"> name</span><span class="special">;</span><span class="keyword">
float</span><span class="identifier"> value</span><span class="special">;</span><span class="special">
};</span></tt></pre>
<p>
Our C++ <tt class="literal">Var</tt> class and its data members can be exposed to Python:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">class_</span><span class="special">&lt;</span><span class="identifier">Var</span><span class="special">&gt;(</span><span class="string">"Var"</span><span class="special">,</span><span class="identifier"> init</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&gt;())</span><span class="special">
.</span><span class="identifier">def_readonly</span><span class="special">(</span><span class="string">"name"</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">Var</span><span class="special">::</span><span class="identifier">name</span><span class="special">)</span><span class="special">
.</span><span class="identifier">def_readwrite</span><span class="special">(</span><span class="string">"value"</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">Var</span><span class="special">::</span><span class="identifier">value</span><span class="special">);</span></tt></pre>
<p>
Then, in Python, assuming we have placed our Var class inside the namespace
hello as we did before:</p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="identifier"> x</span><span class="special"> =</span><span class="identifier"> hello</span><span class="special">.</span><span class="identifier">Var</span><span class="special">(</span><span class="char">'pi'</span><span class="special">)</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> x</span><span class="special">.</span><span class="identifier">value</span><span class="special"> =</span><span class="number"> 3.14</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> print</span><span class="identifier"> x</span><span class="special">.</span><span class="identifier">name</span><span class="special">,</span><span class="char"> 'is around'</span><span class="special">,</span><span class="identifier"> x</span><span class="special">.</span><span class="identifier">value</span><span class="identifier">
pi</span><span class="identifier"> is</span><span class="identifier"> around</span><span class="number"> 3.14</span></tt></pre>
<p>
Note that <tt class="literal">name</tt> is exposed as <span class="bold"><b>read-only</b></span> while <tt class="literal">value</tt> is exposed
as <span class="bold"><b>read-write</b></span>.</p>
<pre class="programlisting"><tt class="literal"> &gt;&gt;&gt; x.name = 'e' # can't change name
Traceback (most recent call last):
File "&lt;stdin&gt;", line 1, in ?
AttributeError: can't set attribute
</tt></pre>
</div>
<div class="section" lang="en">
<div class="titlepage">
<div><div><h3 class="title">
<a name="python.class_properties"></a>Class Properties</h3></div></div>
<div></div>
</div>
<p>
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:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">struct</span><span class="identifier"> Num</span><span class="special">
{</span><span class="identifier">
Num</span><span class="special">();</span><span class="keyword">
float</span><span class="identifier"> get</span><span class="special">()</span><span class="keyword"> const</span><span class="special">;</span><span class="keyword">
void</span><span class="identifier"> set</span><span class="special">(</span><span class="keyword">float</span><span class="identifier"> value</span><span class="special">);</span><span class="special">
...</span><span class="special">
};</span></tt></pre>
<p>
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
<tt class="literal">Num</tt> class using Boost.Python:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">class_</span><span class="special">&lt;</span><span class="identifier">Num</span><span class="special">&gt;(</span><span class="string">"Num"</span><span class="special">)</span><span class="special">
.</span><span class="identifier">add_property</span><span class="special">(</span><span class="string">"rovalue"</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">Num</span><span class="special">::</span><span class="identifier">get</span><span class="special">)</span><span class="special">
.</span><span class="identifier">add_property</span><span class="special">(</span><span class="string">"value"</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">Num</span><span class="special">::</span><span class="identifier">get</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">Num</span><span class="special">::</span><span class="identifier">set</span><span class="special">);</span></tt></pre>
<p>
And at last, in Python:</p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="identifier"> x</span><span class="special"> =</span><span class="identifier"> Num</span><span class="special">()</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> x</span><span class="special">.</span><span class="identifier">value</span><span class="special"> =</span><span class="number"> 3.14</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> x</span><span class="special">.</span><span class="identifier">value</span><span class="special">,</span><span class="identifier"> x</span><span class="special">.</span><span class="identifier">rovalue</span><span class="special">
(</span><span class="number">3.14</span><span class="special">,</span><span class="number"> 3.14</span><span class="special">)</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> x</span><span class="special">.</span><span class="identifier">rovalue</span><span class="special"> =</span><span class="number"> 2.17</span> #<span class="identifier"> error</span><span class="special">!</span></tt></pre>
<p>
Take note that the class property <tt class="literal">rovalue</tt> is exposed as <span class="bold"><b>read-only</b></span>
since the <tt class="literal">rovalue</tt> setter member function is not passed in:</p>
<pre class="programlisting"><tt class="literal"><span class="special">.</span><span class="identifier">add_property</span><span class="special">(</span><span class="string">"rovalue"</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">Num</span><span class="special">::</span><span class="identifier">get</span><span class="special">)</span></tt></pre>
</div>
<div class="section" lang="en">
<div class="titlepage">
<div><div><h3 class="title">
<a name="python.inheritance"></a>Inheritance</h3></div></div>
<div></div>
</div>
<p>
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.</p>
<p>
Consider this trivial inheritance structure:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">struct</span><span class="identifier"> Base</span><span class="special"> {</span><span class="keyword"> virtual</span><span class="special"> ~</span><span class="identifier">Base</span><span class="special">();</span><span class="special"> };</span><span class="keyword">
struct</span><span class="identifier"> Derived</span><span class="special"> :</span><span class="identifier"> Base</span><span class="special"> {};</span></tt></pre>
<p>
And a set of C++ functions operating on <tt class="literal">Base</tt> and <tt class="literal">Derived</tt> object
instances:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">void</span><span class="identifier"> b</span><span class="special">(</span><span class="identifier">Base</span><span class="special">*);</span><span class="keyword">
void</span><span class="identifier"> d</span><span class="special">(</span><span class="identifier">Derived</span><span class="special">*);</span><span class="identifier">
Base</span><span class="special">*</span><span class="identifier"> factory</span><span class="special">()</span><span class="special"> {</span><span class="keyword"> return</span><span class="keyword"> new</span><span class="identifier"> Derived</span><span class="special">;</span><span class="special"> }</span></tt></pre>
<p>
We've seen how we can wrap the base class <tt class="literal">Base</tt>:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">class_</span><span class="special">&lt;</span><span class="identifier">Base</span><span class="special">&gt;(</span><span class="string">"Base"</span><span class="special">)</span><span class="comment">
/*...*/</span><span class="special">
;</span></tt></pre>
<p>
Now we can inform Boost.Python of the inheritance relationship between
<tt class="literal">Derived</tt> and its base class <tt class="literal">Base</tt>. Thus:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">class_</span><span class="special">&lt;</span><span class="identifier">Derived</span><span class="special">,</span><span class="identifier"> bases</span><span class="special">&lt;</span><span class="identifier">Base</span><span class="special">&gt;</span><span class="special"> &gt;(</span><span class="string">"Derived"</span><span class="special">)</span><span class="comment">
/*...*/</span><span class="special">
;</span></tt></pre>
<p>
Doing so, we get some things for free:</p>
<div class="orderedlist"><ol type="1">
<li>
Derived automatically inherits all of Base's Python methods (wrapped C++ member functions)
</li>
<li>
<span class="bold"><b>If</b></span> Base is polymorphic, <tt class="literal">Derived</tt> objects which have been passed to Python via a pointer or reference to <tt class="literal">Base</tt> can be passed where a pointer or reference to <tt class="literal">Derived</tt> is expected.
</li>
</ol></div>
<p>
Now, we shall expose the C++ free functions <tt class="literal">b</tt> and <tt class="literal">d</tt> and <tt class="literal">factory</tt>:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">def</span><span class="special">(</span><span class="string">"b"</span><span class="special">,</span><span class="identifier"> b</span><span class="special">);</span><span class="identifier">
def</span><span class="special">(</span><span class="string">"d"</span><span class="special">,</span><span class="identifier"> d</span><span class="special">);</span><span class="identifier">
def</span><span class="special">(</span><span class="string">"factory"</span><span class="special">,</span><span class="identifier"> factory</span><span class="special">);</span></tt></pre>
<p>
Note that free function <tt class="literal">factory</tt> is being used to generate new
instances of class <tt class="literal">Derived</tt>. In such cases, we use
<tt class="literal">return_value_policy&lt;manage_new_object&gt;</tt> to instruct Python to adopt
the pointer to <tt class="literal">Base</tt> and hold the instance in a new Python <tt class="literal">Base</tt>
object until the the Python object is destroyed. We shall see more of
Boost.Python <a href="functions.html#python.call_policies" target="_top">call policies</a> later.</p>
<pre class="programlisting"><tt class="literal"><span class="comment">// Tell Python to take ownership of factory's result
</span><span class="identifier">def</span><span class="special">(</span><span class="string">"factory"</span><span class="special">,</span><span class="identifier"> factory</span><span class="special">,</span><span class="identifier">
return_value_policy</span><span class="special">&lt;</span><span class="identifier">manage_new_object</span><span class="special">&gt;());</span></tt></pre>
</div>
<div class="section" lang="en">
<div class="titlepage">
<div><div><h3 class="title">
<a name="python.class_virtual_functions"></a>Class Virtual Functions</h3></div></div>
<div></div>
</div>
<p>
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 <tt class="literal">Base</tt> class:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">struct</span><span class="identifier"> Base</span><span class="special">
{</span><span class="keyword">
virtual</span><span class="keyword"> int</span><span class="identifier"> f</span><span class="special">()</span><span class="special"> =</span><span class="number"> 0</span><span class="special">;</span><span class="special">
};</span></tt></pre>
<p>
Since <tt class="literal">f</tt> is a pure virtual function, <tt class="literal">Base</tt> is now an abstract
class. Given an instance of our class, the free function <tt class="literal">call_f</tt>
calls some implementation of this virtual function in a concrete
derived class:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">int</span><span class="identifier"> call_f</span><span class="special">(</span><span class="identifier">Base</span><span class="special">&amp;</span><span class="identifier"> b</span><span class="special">)</span><span class="special"> {</span><span class="keyword"> return</span><span class="identifier"> b</span><span class="special">.</span><span class="identifier">f</span><span class="special">();</span><span class="special"> }</span></tt></pre>
<p>
To allow this function to be implemented in a Python derived class, we
need to create a class wrapper:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">struct</span><span class="identifier"> BaseWrap</span><span class="special"> :</span><span class="identifier"> Base</span><span class="special">
{</span><span class="identifier">
BaseWrap</span><span class="special">(</span><span class="identifier">PyObject</span><span class="special">*</span><span class="identifier"> self_</span><span class="special">)</span><span class="special">
:</span><span class="identifier"> self</span><span class="special">(</span><span class="identifier">self_</span><span class="special">)</span><span class="special"> {}</span><span class="keyword">
int</span><span class="identifier"> f</span><span class="special">()</span><span class="special"> {</span><span class="keyword"> return</span><span class="identifier"> call_method</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;(</span><span class="identifier">self</span><span class="special">,</span><span class="string"> "f"</span><span class="special">);</span><span class="special"> }</span><span class="identifier">
PyObject</span><span class="special">*</span><span class="identifier"> self</span><span class="special">;</span><span class="special">
};</span><span class="keyword">
struct</span><span class="identifier"> BaseWrap</span><span class="special"> :</span><span class="identifier"> Base</span><span class="special">
{</span><span class="identifier">
BaseWrap</span><span class="special">(</span><span class="identifier">PyObject</span><span class="special">*</span><span class="identifier"> self_</span><span class="special">)</span><span class="special">
:</span><span class="identifier"> self</span><span class="special">(</span><span class="identifier">self_</span><span class="special">)</span><span class="special"> {}</span><span class="identifier">
BaseWrap</span><span class="special">(</span><span class="identifier">PyObject</span><span class="special">*</span><span class="identifier"> self_</span><span class="special">,</span><span class="identifier"> Base</span><span class="keyword"> const</span><span class="special">&amp;</span><span class="identifier"> copy</span><span class="special">)</span><span class="special">
:</span><span class="identifier"> Base</span><span class="special">(</span><span class="identifier">copy</span><span class="special">),</span><span class="identifier"> self</span><span class="special">(</span><span class="identifier">self_</span><span class="special">)</span><span class="special"> {}</span><span class="keyword">
int</span><span class="identifier"> f</span><span class="special">()</span><span class="special"> {</span><span class="keyword"> return</span><span class="identifier"> call_method</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;(</span><span class="identifier">self</span><span class="special">,</span><span class="string"> "f"</span><span class="special">);</span><span class="special"> }</span><span class="keyword">
int</span><span class="identifier"> default_f</span><span class="special">()</span><span class="special"> {</span><span class="keyword"> return</span><span class="identifier"> Base</span><span class="special">::</span><span class="identifier">f</span><span class="special">();</span><span class="special"> }</span><span class="comment"> // &lt;&lt;=== ***ADDED***
</span><span class="identifier"> PyObject</span><span class="special">*</span><span class="identifier"> self</span><span class="special">;</span><span class="special">
};</span></tt></pre>
<div class="informaltable"><table class="table">
<colgroup><col></colgroup>
<tbody><tr><td>
<span class="inlinemediaobject"><img src="../images/note.png"></span><span class="bold"><b>member function and methods</b></span><p></p>
<p></p>
Python, like
many object oriented languages uses the term <span class="bold"><b>methods</b></span>. Methods
correspond roughly to C++'s <span class="bold"><b>member functions</b></span>
</td></tr></tbody>
</table></div>
<p>
Our class wrapper <tt class="literal">BaseWrap</tt> is derived from <tt class="literal">Base</tt>. Its overridden
virtual member function <tt class="literal">f</tt> in effect calls the corresponding method
of the Python object <tt class="literal">self</tt>, which is a pointer back to the Python
<tt class="literal">Base</tt> object holding our <tt class="literal">BaseWrap</tt> instance.</p>
<div class="informaltable"><table class="table">
<colgroup><col></colgroup>
<tbody><tr><td>
<span class="inlinemediaobject"><img src="../images/note.png"></span><span class="bold"><b>Why do we need BaseWrap?</b></span><p></p>
<p></p>
</td></tr></tbody>
</table></div>
<p><span class="emphasis"><em>You may ask</em></span>, "Why do we need the <tt class="literal">BaseWrap</tt> derived class? This could
have been designed so that everything gets done right inside of
Base."</p>
<p></p>
<p></p>
<p>
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.</p>
<p></p>
<p></p>
<p>
Note however that you don't need to do this to get methods overridden
in Python to behave virtually when called <span class="emphasis"><em>from</em></span><span class="bold"><b>Python</b></span>. The only
time you need to do the <tt class="literal">BaseWrap</tt> dance is when you have a virtual
function that's going to be overridden in Python and called
polymorphically <span class="emphasis"><em>from</em></span><span class="bold"><b>C++</b></span>.]</p>
<p>
Wrapping <tt class="literal">Base</tt> and the free function <tt class="literal">call_f</tt>:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">class_</span><span class="special">&lt;</span><span class="identifier">Base</span><span class="special">,</span><span class="identifier"> BaseWrap</span><span class="special">,</span><span class="identifier"> boost</span><span class="special">::</span><span class="identifier">noncopyable</span><span class="special">&gt;(</span><span class="string">"Base"</span><span class="special">,</span><span class="identifier"> no_init</span><span class="special">)</span><span class="special">
;</span><span class="identifier">
def</span><span class="special">(</span><span class="string">"call_f"</span><span class="special">,</span><span class="identifier"> call_f</span><span class="special">);</span></tt></pre>
<p>
Notice that we parameterized the <tt class="literal">class_</tt> template with <tt class="literal">BaseWrap</tt> as the
second parameter. What is <tt class="literal">noncopyable</tt>? 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.</p>
<p>
In Python, let us try to instantiate our <tt class="literal">Base</tt> class:</p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="identifier"> base</span><span class="special"> =</span><span class="identifier"> Base</span><span class="special">()</span><span class="identifier">
RuntimeError</span><span class="special">:</span><span class="identifier"> This</span><span class="keyword"> class</span><span class="identifier"> cannot</span><span class="identifier"> be</span><span class="identifier"> instantiated</span><span class="identifier"> from</span><span class="identifier"> Python</span></tt></pre>
<p>
Why is it an error? <tt class="literal">Base</tt> is an abstract class. As such it is advisable
to define the Python wrapper with <tt class="literal">no_init</tt> as we have done above. Doing
so will disallow abstract base classes such as <tt class="literal">Base</tt> to be instantiated.</p>
</div>
<div class="section" lang="en">
<div class="titlepage">
<div><div><h3 class="title">
<a name="python.deriving_a_python_class"></a>Deriving a Python Class</h3></div></div>
<div></div>
</div>
<p>
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 <tt class="literal">class_</tt> wrapper as:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">class_</span><span class="special">&lt;</span><span class="identifier">Base</span><span class="special">,</span><span class="identifier"> BaseWrap</span><span class="special">,</span><span class="identifier"> boost</span><span class="special">::</span><span class="identifier">noncopyable</span><span class="special">&gt;(</span><span class="string">"Base"</span><span class="special">)</span><span class="special">
;</span></tt></pre>
<p>
Otherwise, we have to suppress the Base class' <tt class="literal">no_init</tt> by adding an
<tt class="literal"><span class="underline">_init</span>_()</tt> method to all our derived classes. <tt class="literal">no_init</tt> actually adds
an <tt class="literal"><span class="underline">_init</span>_</tt> method that raises a Python RuntimeError exception.</p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="keyword"> class</span><span class="identifier"> Derived</span><span class="special">(</span><span class="identifier">Base</span><span class="special">):</span><span class="special">
...</span><span class="identifier"> def</span><span class="identifier"> f</span><span class="special">(</span><span class="identifier">self</span><span class="special">):</span><span class="special">
...</span><span class="keyword"> return</span><span class="number"> 42</span><span class="special">
...</span></tt></pre>
<p>
Cool eh? A Python class deriving from a C++ class!</p>
<p>
Let's now make an instance of our Python class <tt class="literal">Derived</tt>:</p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="identifier"> derived</span><span class="special"> =</span><span class="identifier"> Derived</span><span class="special">()</span></tt></pre>
<p>
Calling <tt class="literal">derived.f()</tt>:</p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="identifier"> derived</span><span class="special">.</span><span class="identifier">f</span><span class="special">()</span><span class="number">
42</span></tt></pre>
<p>
Will yield the expected result. Finally, calling calling the free function
<tt class="literal">call_f</tt> with <tt class="literal">derived</tt> as argument:</p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="identifier"> call_f</span><span class="special">(</span><span class="identifier">derived</span><span class="special">)</span><span class="number">
42</span></tt></pre>
<p>
Will also yield the expected result.</p>
<p>
Here's what's happening:</p>
<div class="orderedlist"><ol type="1">
<li>
<tt class="literal">call_f(derived)</tt> is called in Python
</li>
<li>
This corresponds to <tt class="literal">def("call_f", call_f);</tt>. Boost.Python dispatches this call.
</li>
<li>
<tt class="literal">int call_f(Base&amp; b) { return b.f(); }</tt> accepts the call.
</li>
<li>
The overridden virtual function <tt class="literal">f</tt> of <tt class="literal">BaseWrap</tt> is called.
</li>
<li>
<tt class="literal">call_method&lt;int&gt;(self, "f");</tt> dispatches the call back to Python.
</li>
<li>
<tt class="literal">def f(self): return 42</tt> is finally called.
</li>
</ol></div>
</div>
<div class="section" lang="en">
<div class="titlepage">
<div><div><h3 class="title">
<a name="python.virtual_functions_with_default_implementations"></a>Virtual Functions with Default Implementations</h3></div></div>
<div></div>
</div>
<p>
Recall that in the <a href="exposing.html#class_virtual_functions" target="_top">previous section</a>, we
wrapped a class with a pure virtual function that we then implemented in
C++ or Python classes derived from it. Our base class:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">struct</span><span class="identifier"> Base</span><span class="special">
{</span><span class="keyword">
virtual</span><span class="keyword"> int</span><span class="identifier"> f</span><span class="special">()</span><span class="special"> =</span><span class="number"> 0</span><span class="special">;</span><span class="special">
};</span></tt></pre>
<p>
had a pure virtual function <tt class="literal">f</tt>. If, however, its member function <tt class="literal">f</tt> was
not declared as pure virtual:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">struct</span><span class="identifier"> Base</span><span class="special">
{</span><span class="keyword">
virtual</span><span class="keyword"> int</span><span class="identifier"> f</span><span class="special">()</span><span class="special"> {</span><span class="keyword"> return</span><span class="number"> 0</span><span class="special">;</span><span class="special"> }</span><span class="special">
};</span></tt></pre>
<p>
and instead had a default implementation that returns <tt class="literal">0</tt>, as shown above,
we need to add a forwarding function that calls the <tt class="literal">Base</tt> default virtual
function <tt class="literal">f</tt> implementation:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">struct</span><span class="identifier"> BaseWrap</span><span class="special"> :</span><span class="identifier"> Base</span><span class="special">
{</span><span class="identifier">
BaseWrap</span><span class="special">(</span><span class="identifier">PyObject</span><span class="special">*</span><span class="identifier"> self_</span><span class="special">)</span><span class="special">
:</span><span class="identifier"> self</span><span class="special">(</span><span class="identifier">self_</span><span class="special">)</span><span class="special"> {}</span><span class="keyword">
int</span><span class="identifier"> f</span><span class="special">()</span><span class="special"> {</span><span class="keyword"> return</span><span class="identifier"> call_method</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;(</span><span class="identifier">self</span><span class="special">,</span><span class="string"> "f"</span><span class="special">);</span><span class="special"> }</span><span class="keyword">
int</span><span class="identifier"> default_f</span><span class="special">()</span><span class="special"> {</span><span class="keyword"> return</span><span class="identifier"> Base</span><span class="special">::</span><span class="identifier">f</span><span class="special">();</span><span class="special"> }</span><span class="comment"> // &lt;&lt;=== ***ADDED***
</span><span class="identifier"> PyObject</span><span class="special">*</span><span class="identifier"> self</span><span class="special">;</span><span class="special">
};</span></tt></pre>
<p>
Then, Boost.Python needs to keep track of 1) the dispatch function <tt class="literal">f</tt> and
2) the forwarding function to its default implementation <tt class="literal">default_f</tt>.
There's a special <tt class="literal">def</tt> function for this purpose. Here's how it is
applied to our example above:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">class_</span><span class="special">&lt;</span><span class="identifier">Base</span><span class="special">,</span><span class="identifier"> BaseWrap</span><span class="special">,</span><span class="identifier"> BaseWrap</span><span class="special">,</span><span class="identifier"> boost</span><span class="special">::</span><span class="identifier">noncopyable</span><span class="special">&gt;(</span><span class="string">"Base"</span><span class="special">)</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">Base</span><span class="special">::</span><span class="identifier">f</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">BaseWrap</span><span class="special">::</span><span class="identifier">default_f</span><span class="special">)</span></tt></pre>
<p>
Note that we are allowing <tt class="literal">Base</tt> objects to be instantiated this time,
unlike before where we specifically defined the <tt class="literal">class_&lt;Base&gt;</tt> with
<tt class="literal">no_init</tt>.</p>
<p>
In Python, the results would be as expected:</p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="identifier"> base</span><span class="special"> =</span><span class="identifier"> Base</span><span class="special">()</span><span class="special">
&gt;&gt;&gt;</span><span class="keyword"> class</span><span class="identifier"> Derived</span><span class="special">(</span><span class="identifier">Base</span><span class="special">):</span><span class="special">
...</span><span class="identifier"> def</span><span class="identifier"> f</span><span class="special">(</span><span class="identifier">self</span><span class="special">):</span><span class="special">
...</span><span class="keyword"> return</span><span class="number"> 42</span><span class="special">
...</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> derived</span><span class="special"> =</span><span class="identifier"> Derived</span><span class="special">()</span></tt></pre>
<p>
Calling <tt class="literal">base.f()</tt>:</p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="identifier"> base</span><span class="special">.</span><span class="identifier">f</span><span class="special">()</span><span class="number">
0</span></tt></pre>
<p>
Calling <tt class="literal">derived.f()</tt>:</p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="identifier"> derived</span><span class="special">.</span><span class="identifier">f</span><span class="special">()</span><span class="number">
42</span></tt></pre>
<p>
Calling <tt class="literal">call_f</tt>, passing in a <tt class="literal">base</tt> object:</p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="identifier"> call_f</span><span class="special">(</span><span class="identifier">base</span><span class="special">)</span><span class="number">
0</span></tt></pre>
<p>
Calling <tt class="literal">call_f</tt>, passing in a <tt class="literal">derived</tt> object:</p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="identifier"> call_f</span><span class="special">(</span><span class="identifier">derived</span><span class="special">)</span><span class="number">
42</span></tt></pre>
</div>
<div class="section" lang="en">
<div class="titlepage">
<div><div><h3 class="title">
<a name="python.class_operators_special_functions"></a>Class Operators/Special Functions</h3></div></div>
<div></div>
</div>
<a name="class_operators_special_functions.python_operators"></a><h2>
<a name="id420103"></a>Python Operators</h2>
<p>
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.</p>
<p>
Consider a file position class <tt class="literal">FilePos</tt> and a set of operators that take
on FilePos instances:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">class</span><span class="identifier"> FilePos</span><span class="special"> {</span><span class="comment"> /*...*/</span><span class="special"> };</span><span class="identifier">
FilePos</span><span class="keyword"> operator</span><span class="special">+(</span><span class="identifier">FilePos</span><span class="special">,</span><span class="keyword"> int</span><span class="special">);</span><span class="identifier">
FilePos</span><span class="keyword"> operator</span><span class="special">+(</span><span class="keyword">int</span><span class="special">,</span><span class="identifier"> FilePos</span><span class="special">);</span><span class="keyword">
int</span><span class="keyword"> operator</span><span class="special">-(</span><span class="identifier">FilePos</span><span class="special">,</span><span class="identifier"> FilePos</span><span class="special">);</span><span class="identifier">
FilePos</span><span class="keyword"> operator</span><span class="special">-(</span><span class="identifier">FilePos</span><span class="special">,</span><span class="keyword"> int</span><span class="special">);</span><span class="identifier">
FilePos</span><span class="special">&amp;</span><span class="keyword"> operator</span><span class="special">+=(</span><span class="identifier">FilePos</span><span class="special">&amp;,</span><span class="keyword"> int</span><span class="special">);</span><span class="identifier">
FilePos</span><span class="special">&amp;</span><span class="keyword"> operator</span><span class="special">-=(</span><span class="identifier">FilePos</span><span class="special">&amp;,</span><span class="keyword"> int</span><span class="special">);</span><span class="keyword">
bool</span><span class="keyword"> operator</span><span class="special">&lt;(</span><span class="identifier">FilePos</span><span class="special">,</span><span class="identifier"> FilePos</span><span class="special">);</span></tt></pre>
<p>
The class and the various operators can be mapped to Python rather easily
and intuitively:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">class_</span><span class="special">&lt;</span><span class="identifier">FilePos</span><span class="special">&gt;(</span><span class="string">"FilePos"</span><span class="special">)</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">self</span><span class="special"> +</span><span class="keyword"> int</span><span class="special">())</span><span class="comment"> // __add__
</span><span class="special"> .</span><span class="identifier">def</span><span class="special">(</span><span class="keyword">int</span><span class="special">()</span><span class="special"> +</span><span class="identifier"> self</span><span class="special">)</span><span class="comment"> // __radd__
</span><span class="special"> .</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">self</span><span class="special"> -</span><span class="identifier"> self</span><span class="special">)</span><span class="comment"> // __sub__
</span><span class="special"> .</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">self</span><span class="special"> -</span><span class="keyword"> int</span><span class="special">())</span><span class="comment"> // __sub__
</span><span class="special"> .</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">self</span><span class="special"> +=</span><span class="keyword"> int</span><span class="special">())</span><span class="comment"> // __iadd__
</span><span class="special"> .</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">self</span><span class="special"> -=</span><span class="identifier"> other</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;())</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">self</span><span class="special"> &lt;</span><span class="identifier"> self</span><span class="special">);</span><span class="comment"> // __lt__
</span></tt></pre>
<p>
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 <tt class="literal">self</tt> refers to FilePos object. Also, not every class <tt class="literal">T</tt> that
you might need to interact with in an operator expression is (cheaply)
default-constructible. You can use <tt class="literal">other&lt;T&gt;()</tt> in place of an actual
<tt class="literal">T</tt> instance when writing "self expressions".</p>
<a name="class_operators_special_functions.special_methods"></a><h2>
<a name="id420789"></a>Special Methods</h2>
<p>
Python has a few more <span class="emphasis"><em>Special Methods</em></span>. 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 <span class="emphasis"><em>special functions</em></span>. Example:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">class</span><span class="identifier"> Rational</span><span class="special">
{</span><span class="keyword"> operator</span><span class="keyword"> double</span><span class="special">()</span><span class="keyword"> const</span><span class="special">;</span><span class="special"> };</span><span class="identifier">
Rational</span><span class="identifier"> pow</span><span class="special">(</span><span class="identifier">Rational</span><span class="special">,</span><span class="identifier"> Rational</span><span class="special">);</span><span class="identifier">
Rational</span><span class="identifier"> abs</span><span class="special">(</span><span class="identifier">Rational</span><span class="special">);</span><span class="identifier">
ostream</span><span class="special">&amp;</span><span class="keyword"> operator</span><span class="special">&lt;&lt;(</span><span class="identifier">ostream</span><span class="special">&amp;,</span><span class="identifier">Rational</span><span class="special">);</span><span class="identifier">
class_</span><span class="special">&lt;</span><span class="identifier">Rational</span><span class="special">&gt;()</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">float_</span><span class="special">(</span><span class="identifier">self</span><span class="special">))</span><span class="comment"> // __float__
</span><span class="special"> .</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">pow</span><span class="special">(</span><span class="identifier">self</span><span class="special">,</span><span class="identifier"> other</span><span class="special">&lt;</span><span class="identifier">Rational</span><span class="special">&gt;))</span><span class="comment"> // __pow__
</span><span class="special"> .</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">abs</span><span class="special">(</span><span class="identifier">self</span><span class="special">))</span><span class="comment"> // __abs__
</span><span class="special"> .</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">str</span><span class="special">(</span><span class="identifier">self</span><span class="special">))</span><span class="comment"> // __str__
</span><span class="special"> ;</span></tt></pre>
<p>
Need we say more?</p>
<div class="informaltable"><table class="table">
<colgroup><col></colgroup>
<tbody><tr><td>
<span class="inlinemediaobject"><img src="../images/note.png"></span> What is the business of <tt class="literal">operator&lt;&lt;</tt><tt class="literal">.def(str(self))</tt>?
Well, the method <tt class="literal">str</tt> requires the <tt class="literal">operator&lt;&lt;</tt> to do its work (i.e.
<tt class="literal">operator&lt;&lt;</tt> is used by the method defined by def(str(self)).</td></tr></tbody>
</table></div>
</div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><small>Copyright © 2002-2004 Joel de Guzman, David Abrahams</small></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="hello.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="functions.html"><img src="../images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -0,0 +1,494 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Functions</title>
<link rel="stylesheet" href="../boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.65.1">
<link rel="home" href="../index.html" title="Chapter 1. python 1.0">
<link rel="up" href="../index.html" title="Chapter 1. python 1.0">
<link rel="previous" href="exposing.html" title=" Exposing Classes">
<link rel="next" href="object.html" title=" Object Interface">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%">
<td valign="top"><img alt="boost.png (6897 bytes)" width="277" height="86" src="../../../boost.png"></td>
<td align="center"><a href="../../../index.htm">Home</a></td>
<td align="center"><a href="../libraries.html">Libraries</a></td>
<td align="center"><a href="../../../people/people.htm">People</a></td>
<td align="center"><a href="../../../more/faq.htm">FAQ</a></td>
<td align="center"><a href="../../../more/index.htm">More</a></td>
</table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="exposing.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="object.html"><img src="../images/next.png" alt="Next"></a>
</div>
<div class="section" lang="en">
<div class="titlepage">
<div><div><h2 class="title" style="clear: both">
<a name="python.functions"></a>Functions</h2></div></div>
<div></div>
</div>
<div class="toc"><dl>
<dt><span class="section"><a href="functions.html#python.call_policies">Call Policies</a></span></dt>
<dt><span class="section"><a href="functions.html#python.overloading">Overloading</a></span></dt>
<dt><span class="section"><a href="functions.html#python.default_arguments">Default Arguments</a></span></dt>
<dt><span class="section"><a href="functions.html#python.auto_overloading">Auto-Overloading</a></span></dt>
</dl></div>
<p>
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.</p>
<div class="blockquote"><blockquote class="blockquote"><p><span class="emphasis"><em>Read on...</em></span></p></blockquote></div>
<p>
But before you do, you might want to fire up Python 2.2 or later and type
<tt class="literal">&gt;&gt;&gt; import this</tt>.</p>
<pre class="programlisting"><tt class="literal"> &gt;&gt;&gt; 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 <span class="bold"><b>right</b></span> 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!
</tt></pre>
<div class="section" lang="en">
<div class="titlepage">
<div><div><h3 class="title">
<a name="python.call_policies"></a>Call Policies</h3></div></div>
<div></div>
</div>
<p>
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:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">X</span><span class="special">&amp;</span><span class="identifier"> f</span><span class="special">(</span><span class="identifier">Y</span><span class="special">&amp;</span><span class="identifier"> y</span><span class="special">,</span><span class="identifier"> Z</span><span class="special">*</span><span class="identifier"> z</span><span class="special">);</span></tt></pre>
<p>
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</p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="identifier"> x</span><span class="special"> =</span><span class="identifier"> f</span><span class="special">(</span><span class="identifier">y</span><span class="special">,</span><span class="identifier"> z</span><span class="special">)</span> #<span class="identifier"> x</span><span class="identifier"> refers</span><span class="identifier"> to</span><span class="identifier"> some</span><span class="identifier"> C</span><span class="special">++</span><span class="identifier"> X</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> del</span><span class="identifier"> y</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> x</span><span class="special">.</span><span class="identifier">some_method</span><span class="special">()</span> #<span class="identifier"> CRASH</span><span class="special">!</span></tt></pre>
<p>
What's the problem?</p>
<p>
Well, what if f() was implemented as shown below:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">X</span><span class="special">&amp;</span><span class="identifier"> f</span><span class="special">(</span><span class="identifier">Y</span><span class="special">&amp;</span><span class="identifier"> y</span><span class="special">,</span><span class="identifier"> Z</span><span class="special">*</span><span class="identifier"> z</span><span class="special">)</span><span class="special">
{</span><span class="identifier">
y</span><span class="special">.</span><span class="identifier">z</span><span class="special"> =</span><span class="identifier"> z</span><span class="special">;</span><span class="keyword">
return</span><span class="identifier"> y</span><span class="special">.</span><span class="identifier">x</span><span class="special">;</span><span class="special">
}</span></tt></pre>
<p>
The problem is that the lifetime of result X&amp; 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.</p>
<p>
Here's what's happening:</p>
<div class="orderedlist"><ol type="1">
<li>
<tt class="literal">f</tt> is called passing in a reference to <tt class="literal">y</tt> and a pointer to <tt class="literal">z</tt>
</li>
<li>
A reference to <tt class="literal">y.x</tt> is returned
</li>
<li>
<tt class="literal">y</tt> is deleted. <tt class="literal">x</tt> is a dangling reference
</li>
<li>
<tt class="literal">x.some_method()</tt> is called
</li>
<li><span class="bold"><b>BOOM!</b></span></li>
</ol></div>
<p>
We could copy result into a new object:</p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="identifier"> f</span><span class="special">(</span><span class="identifier">y</span><span class="special">,</span><span class="identifier"> z</span><span class="special">).</span><span class="identifier">set</span><span class="special">(</span><span class="number">42</span><span class="special">)</span> #<span class="identifier"> Result</span><span class="identifier"> disappears</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> y</span><span class="special">.</span><span class="identifier">x</span><span class="special">.</span><span class="identifier">get</span><span class="special">()</span>       #<span class="identifier"> No</span><span class="identifier"> crash</span><span class="special">,</span><span class="identifier"> but</span><span class="identifier"> still</span><span class="identifier"> bad</span><span class="number">
3.14</span></tt></pre>
<p>
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.</p>
<p>
Our problems do not end there. Suppose Y is implemented as follows:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">struct</span><span class="identifier"> Y</span><span class="special">
{</span><span class="identifier">
X</span><span class="identifier"> x</span><span class="special">;</span><span class="identifier"> Z</span><span class="special">*</span><span class="identifier"> z</span><span class="special">;</span><span class="keyword">
int</span><span class="identifier"> z_value</span><span class="special">()</span><span class="special"> {</span><span class="keyword"> return</span><span class="identifier"> z</span><span class="special">-&gt;</span><span class="identifier">value</span><span class="special">();</span><span class="special"> }</span><span class="special">
};</span></tt></pre>
<p>
Notice that the data member <tt class="literal">z</tt> is held by class Y using a raw
pointer. Now we have a potential dangling pointer problem inside Y:</p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="identifier"> x</span><span class="special"> =</span><span class="identifier"> f</span><span class="special">(</span><span class="identifier">y</span><span class="special">,</span><span class="identifier"> z</span><span class="special">)</span> #<span class="identifier"> y</span><span class="identifier"> refers</span><span class="identifier"> to</span><span class="identifier"> z</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> del</span><span class="identifier"> z</span>       #<span class="identifier"> Kill</span><span class="identifier"> the</span><span class="identifier"> z</span><span class="identifier"> object</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> y</span><span class="special">.</span><span class="identifier">z_value</span><span class="special">()</span> #<span class="identifier"> CRASH</span><span class="special">!</span></tt></pre>
<p>
For reference, here's the implementation of <tt class="literal">f</tt> again:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">X</span><span class="special">&amp;</span><span class="identifier"> f</span><span class="special">(</span><span class="identifier">Y</span><span class="special">&amp;</span><span class="identifier"> y</span><span class="special">,</span><span class="identifier"> Z</span><span class="special">*</span><span class="identifier"> z</span><span class="special">)</span><span class="special">
{</span><span class="identifier">
y</span><span class="special">.</span><span class="identifier">z</span><span class="special"> =</span><span class="identifier"> z</span><span class="special">;</span><span class="keyword">
return</span><span class="identifier"> y</span><span class="special">.</span><span class="identifier">x</span><span class="special">;</span><span class="special">
}</span></tt></pre>
<p>
Here's what's happening:</p>
<div class="orderedlist"><ol type="1">
<li>
<tt class="literal">f</tt> is called passing in a reference to <tt class="literal">y</tt> and a pointer to <tt class="literal">z</tt>
</li>
<li>
A pointer to <tt class="literal">z</tt> is held by <tt class="literal">y</tt>
</li>
<li>
A reference to <tt class="literal">y.x</tt> is returned
</li>
<li>
<tt class="literal">z</tt> is deleted. <tt class="literal">y.z</tt> is a dangling pointer
</li>
<li>
<tt class="literal">y.z_value()</tt> is called
</li>
<li>
<tt class="literal">z-&gt;value()</tt> is called
</li>
<li><span class="bold"><b>BOOM!</b></span></li>
</ol></div>
<a name="call_policies.call_policies"></a><h2>
<a name="id422411"></a>Call Policies</h2>
<p>
Call Policies may be used in situations such as the example detailed above.
In our example, <tt class="literal">return_internal_reference</tt> and <tt class="literal">with_custodian_and_ward</tt>
are our friends:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span><span class="identifier"> f</span><span class="special">,</span><span class="identifier">
return_internal_reference</span><span class="special">&lt;</span><span class="number">1</span><span class="special">,</span><span class="identifier">
with_custodian_and_ward</span><span class="special">&lt;</span><span class="number">1</span><span class="special">,</span><span class="number"> 2</span><span class="special">&gt;</span><span class="special"> &gt;());</span></tt></pre>
<p>
What are the <tt class="literal">1</tt> and <tt class="literal">2</tt> parameters, you ask?</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">return_internal_reference</span><span class="special">&lt;</span><span class="number">1</span></tt></pre>
<p>
Informs Boost.Python that the first argument, in our case <tt class="literal">Y&amp; y</tt>, is the
owner of the returned reference: <tt class="literal">X&amp;</tt>. The "<tt class="literal">1</tt>" simply specifies the
first argument. In short: "return an internal reference <tt class="literal">X&amp;</tt> owned by the
1st argument <tt class="literal">Y&amp; y</tt>".</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">with_custodian_and_ward</span><span class="special">&lt;</span><span class="number">1</span><span class="special">,</span><span class="number"> 2</span><span class="special">&gt;</span></tt></pre>
<p>
Informs Boost.Python that the lifetime of the argument indicated by ward
(i.e. the 2nd argument: <tt class="literal">Z* z</tt>) is dependent on the lifetime of the
argument indicated by custodian (i.e. the 1st argument: <tt class="literal">Y&amp; y</tt>).</p>
<p>
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:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">policy1</span><span class="special">&lt;</span><span class="identifier">args</span><span class="special">...,</span><span class="identifier">
policy2</span><span class="special">&lt;</span><span class="identifier">args</span><span class="special">...,</span><span class="identifier">
policy3</span><span class="special">&lt;</span><span class="identifier">args</span><span class="special">...&gt;</span><span class="special"> &gt;</span><span class="special"> &gt;</span></tt></pre>
<p>
Here is the list of predefined call policies. A complete reference detailing
these can be found <a href="../../../../v2/reference.html#models_of_call_policies" target="_top">here</a>.</p>
<div class="itemizedlist"><ul type="disc">
<li>
<span class="bold"><b>with_custodian_and_ward</b></span><p></p>
Ties lifetimes of the arguments
</li>
<li>
<span class="bold"><b>with_custodian_and_ward_postcall</b></span><p></p>
Ties lifetimes of the arguments and results
</li>
<li>
<span class="bold"><b>return_internal_reference</b></span><p></p>
Ties lifetime of one argument to that of result
</li>
<li>
<span class="bold"><b>return_value_policy&lt;T&gt; with T one of:</b></span><p></p>
</li>
<li>
<span class="bold"><b>reference_existing_object</b></span><p></p>
naive (dangerous) approach
</li>
<li>
<span class="bold"><b>copy_const_reference</b></span><p></p>
Boost.Python v1 approach
</li>
<li>
<span class="bold"><b>copy_non_const_reference</b></span><p></p>
</li>
<li>
<span class="bold"><b>manage_new_object</b></span><p></p>
Adopt a pointer and hold the instance
</li>
</ul></div>
<div class="informaltable"><table class="table">
<colgroup><col></colgroup>
<tbody><tr><td>
<span class="inlinemediaobject"><img src="../images/smiley.png"></span><span class="bold"><b>Remember the Zen, Luke:</b></span><p></p>
<p></p>
"Explicit is better than implicit"<p></p>
"In the face of ambiguity, refuse the temptation to guess"<p></p>
</td></tr></tbody>
</table></div>
</div>
<div class="section" lang="en">
<div class="titlepage">
<div><div><h3 class="title">
<a name="python.overloading"></a>Overloading</h3></div></div>
<div></div>
</div>
<p>
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.</p>
<p>
We have here our C++ class:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">struct</span><span class="identifier"> X</span><span class="special">
{</span><span class="keyword">
bool</span><span class="identifier"> f</span><span class="special">(</span><span class="keyword">int</span><span class="identifier"> a</span><span class="special">)</span><span class="special">
{</span><span class="keyword">
return</span><span class="keyword"> true</span><span class="special">;</span><span class="special">
}</span><span class="keyword">
bool</span><span class="identifier"> f</span><span class="special">(</span><span class="keyword">int</span><span class="identifier"> a</span><span class="special">,</span><span class="keyword"> double</span><span class="identifier"> b</span><span class="special">)</span><span class="special">
{</span><span class="keyword">
return</span><span class="keyword"> true</span><span class="special">;</span><span class="special">
}</span><span class="keyword">
bool</span><span class="identifier"> f</span><span class="special">(</span><span class="keyword">int</span><span class="identifier"> a</span><span class="special">,</span><span class="keyword"> double</span><span class="identifier"> b</span><span class="special">,</span><span class="keyword"> char</span><span class="identifier"> c</span><span class="special">)</span><span class="special">
{</span><span class="keyword">
return</span><span class="keyword"> true</span><span class="special">;</span><span class="special">
}</span><span class="keyword">
int</span><span class="identifier"> f</span><span class="special">(</span><span class="keyword">int</span><span class="identifier"> a</span><span class="special">,</span><span class="keyword"> int</span><span class="identifier"> b</span><span class="special">,</span><span class="keyword"> int</span><span class="identifier"> c</span><span class="special">)</span><span class="special">
{</span><span class="keyword">
return</span><span class="identifier"> a</span><span class="special"> +</span><span class="identifier"> b</span><span class="special"> +</span><span class="identifier"> c</span><span class="special">;</span><span class="special">
};</span><span class="special">
};</span></tt></pre>
<p>
Class X has 4 overloaded functions. We shall start by introducing some
member function pointer variables:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">bool</span><span class="special"> (</span><span class="identifier">X</span><span class="special">::*</span><span class="identifier">fx1</span><span class="special">)(</span><span class="keyword">int</span><span class="special">)</span><span class="special"> =</span><span class="special"> &amp;</span><span class="identifier">X</span><span class="special">::</span><span class="identifier">f</span><span class="special">;</span><span class="keyword">
bool</span><span class="special"> (</span><span class="identifier">X</span><span class="special">::*</span><span class="identifier">fx2</span><span class="special">)(</span><span class="keyword">int</span><span class="special">,</span><span class="keyword"> double</span><span class="special">)</span><span class="special"> =</span><span class="special"> &amp;</span><span class="identifier">X</span><span class="special">::</span><span class="identifier">f</span><span class="special">;</span><span class="keyword">
bool</span><span class="special"> (</span><span class="identifier">X</span><span class="special">::*</span><span class="identifier">fx3</span><span class="special">)(</span><span class="keyword">int</span><span class="special">,</span><span class="keyword"> double</span><span class="special">,</span><span class="keyword"> char</span><span class="special">)=</span><span class="special"> &amp;</span><span class="identifier">X</span><span class="special">::</span><span class="identifier">f</span><span class="special">;</span><span class="keyword">
int</span><span class="special"> (</span><span class="identifier">X</span><span class="special">::*</span><span class="identifier">fx4</span><span class="special">)(</span><span class="keyword">int</span><span class="special">,</span><span class="keyword"> int</span><span class="special">,</span><span class="keyword"> int</span><span class="special">)</span><span class="special"> =</span><span class="special"> &amp;</span><span class="identifier">X</span><span class="special">::</span><span class="identifier">f</span><span class="special">;</span></tt></pre>
<p>
With these in hand, we can proceed to define and wrap this for Python:</p>
<pre class="programlisting"><tt class="literal"><span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span><span class="identifier"> fx1</span><span class="special">)</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span><span class="identifier"> fx2</span><span class="special">)</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span><span class="identifier"> fx3</span><span class="special">)</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span><span class="identifier"> fx4</span><span class="special">)</span></tt></pre>
</div>
<div class="section" lang="en">
<div class="titlepage">
<div><div><h3 class="title">
<a name="python.default_arguments"></a>Default Arguments</h3></div></div>
<div></div>
</div>
<p>
Boost.Python wraps (member) function pointers. Unfortunately, C++ function
pointers carry no default argument info. Take a function <tt class="literal">f</tt> with default
arguments:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">int</span><span class="identifier"> f</span><span class="special">(</span><span class="keyword">int</span><span class="special">,</span><span class="keyword"> double</span><span class="special"> =</span><span class="number"> 3.14</span><span class="special">,</span><span class="keyword"> char</span><span class="keyword"> const</span><span class="special">*</span><span class="special"> =</span><span class="string"> "hello"</span><span class="special">);</span></tt></pre>
<p>
But the type of a pointer to the function <tt class="literal">f</tt> has no information
about its default arguments:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">int</span><span class="special">(*</span><span class="identifier">g</span><span class="special">)(</span><span class="keyword">int</span><span class="special">,</span><span class="keyword">double</span><span class="special">,</span><span class="keyword">char</span><span class="keyword"> const</span><span class="special">*)</span><span class="special"> =</span><span class="identifier"> f</span><span class="special">;</span><span class="comment"> // defaults lost!
</span></tt></pre>
<p>
When we pass this function pointer to the <tt class="literal">def</tt> function, there is no way
to retrieve the default arguments:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span><span class="identifier"> f</span><span class="special">);</span><span class="comment"> // defaults lost!
</span></tt></pre>
<p>
Because of this, when wrapping C++ code, we had to resort to manual
wrapping as outlined in the <a href="functions.html#overloading" target="_top">previous section</a>, or
writing thin wrappers:</p>
<pre class="programlisting"><tt class="literal"><span class="comment">// write "thin wrappers"
</span><span class="keyword">int</span><span class="identifier"> f1</span><span class="special">(</span><span class="keyword">int</span><span class="identifier"> x</span><span class="special">)</span><span class="special"> {</span><span class="identifier"> f</span><span class="special">(</span><span class="identifier">x</span><span class="special">);</span><span class="special"> }</span><span class="keyword">
int</span><span class="identifier"> f2</span><span class="special">(</span><span class="keyword">int</span><span class="identifier"> x</span><span class="special">,</span><span class="keyword"> double</span><span class="identifier"> y</span><span class="special">)</span><span class="special"> {</span><span class="identifier"> f</span><span class="special">(</span><span class="identifier">x</span><span class="special">,</span><span class="identifier">y</span><span class="special">);</span><span class="special"> }</span><span class="comment">
/*...*/
// in module init
</span><span class="identifier"> def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span><span class="identifier"> f</span><span class="special">);</span><span class="comment"> // all arguments
</span><span class="identifier"> def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span><span class="identifier"> f2</span><span class="special">);</span><span class="comment"> // two arguments
</span><span class="identifier"> def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span><span class="identifier"> f1</span><span class="special">);</span><span class="comment"> // one argument
</span></tt></pre>
<p>
When you want to wrap functions (or member functions) that either:</p>
<div class="itemizedlist"><ul type="disc">
<li>
have default arguments, or
</li>
<li>
are overloaded with a common sequence of initial arguments
</li>
</ul></div>
<a name="default_arguments.boost_python_function_overloads"></a><h2>
<a name="id424225"></a>BOOST_PYTHON_FUNCTION_OVERLOADS</h2>
<p>
Boost.Python now has a way to make it easier. For instance, given a function:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">int</span><span class="identifier"> foo</span><span class="special">(</span><span class="keyword">int</span><span class="identifier"> a</span><span class="special">,</span><span class="keyword"> char</span><span class="identifier"> b</span><span class="special"> =</span><span class="number"> 1</span><span class="special">,</span><span class="keyword"> unsigned</span><span class="identifier"> c</span><span class="special"> =</span><span class="number"> 2</span><span class="special">,</span><span class="keyword"> double</span><span class="identifier"> d</span><span class="special"> =</span><span class="number"> 3</span><span class="special">)</span><span class="special">
{</span><span class="comment">
/*...*/</span><span class="special">
}</span></tt></pre>
<p>
The macro invocation:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">BOOST_PYTHON_FUNCTION_OVERLOADS</span><span class="special">(</span><span class="identifier">foo_overloads</span><span class="special">,</span><span class="identifier"> foo</span><span class="special">,</span><span class="number"> 1</span><span class="special">,</span><span class="number"> 4</span><span class="special">)</span></tt></pre>
<p>
will automatically create the thin wrappers for us. This macro will create
a class <tt class="literal">foo_overloads</tt> that can be passed on to <tt class="literal">def(...)</tt>. The third
and fourth macro argument are the minimum arguments and maximum arguments,
respectively. In our <tt class="literal">foo</tt> function the minimum number of arguments is 1
and the maximum number of arguments is 4. The <tt class="literal">def(...)</tt> function will
automatically add all the foo variants for us:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">def</span><span class="special">(</span><span class="string">"foo"</span><span class="special">,</span><span class="identifier"> foo</span><span class="special">,</span><span class="identifier"> foo_overloads</span><span class="special">());</span></tt></pre>
<a name="default_arguments.boost_python_member_function_overloads"></a><h2>
<a name="id424504"></a>BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</h2>
<p>
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.</p>
<p>
Like <tt class="literal">BOOST_PYTHON_FUNCTION_OVERLOADS</tt>,
<tt class="literal">BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</tt> may be used to automatically create
the thin wrappers for wrapping member functions. Let's have an example:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">struct</span><span class="identifier"> george</span><span class="special">
{</span><span class="keyword">
void</span><span class="identifier">
wack_em</span><span class="special">(</span><span class="keyword">int</span><span class="identifier"> a</span><span class="special">,</span><span class="keyword"> int</span><span class="identifier"> b</span><span class="special"> =</span><span class="number"> 0</span><span class="special">,</span><span class="keyword"> char</span><span class="identifier"> c</span><span class="special"> =</span><span class="char"> 'x'</span><span class="special">)</span><span class="special">
{</span><span class="comment">
/*...*/</span><span class="special">
}</span><span class="special">
};</span></tt></pre>
<p>
The macro invocation:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</span><span class="special">(</span><span class="identifier">george_overloads</span><span class="special">,</span><span class="identifier"> wack_em</span><span class="special">,</span><span class="number"> 1</span><span class="special">,</span><span class="number"> 3</span><span class="special">)</span></tt></pre>
<p>
will generate a set of thin wrappers for george's <tt class="literal">wack_em</tt> 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
<tt class="literal">george_overloads</tt> that can then be used as an argument to <tt class="literal">def(...)</tt>:</p>
<pre class="programlisting"><tt class="literal"><span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"wack_em"</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">george</span><span class="special">::</span><span class="identifier">wack_em</span><span class="special">,</span><span class="identifier"> george_overloads</span><span class="special">());</span></tt></pre>
<p>
See the <a href="../../../../v2/overloads.html#BOOST_PYTHON_FUNCTION_OVERLOADS-spec" target="_top">overloads reference</a>
for details.</p>
<a name="default_arguments.init_and_optional"></a><h2>
<a name="id424831"></a>init and optional</h2>
<p>
A similar facility is provided for class constructors, again, with
default arguments or a sequence of overloads. Remember <tt class="literal">init&lt;...&gt;</tt>? For example,
given a class X with a constructor:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">struct</span><span class="identifier"> X</span><span class="special">
{</span><span class="identifier">
X</span><span class="special">(</span><span class="keyword">int</span><span class="identifier"> a</span><span class="special">,</span><span class="keyword"> char</span><span class="identifier"> b</span><span class="special"> =</span><span class="char"> 'D'</span><span class="special">,</span><span class="identifier"> std</span><span class="special">::</span><span class="identifier">string</span><span class="identifier"> c</span><span class="special"> =</span><span class="string"> "constructor"</span><span class="special">,</span><span class="keyword"> double</span><span class="identifier"> d</span><span class="special"> =</span><span class="number"> 0.0</span><span class="special">);</span><span class="comment">
/*...*/</span><span class="special">
}</span></tt></pre>
<p>
You can easily add this constructor to Boost.Python in one shot:</p>
<pre class="programlisting"><tt class="literal"><span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="identifier">init</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">,</span><span class="identifier"> optional</span><span class="special">&lt;</span><span class="keyword">char</span><span class="special">,</span><span class="identifier"> std</span><span class="special">::</span><span class="identifier">string</span><span class="special">,</span><span class="keyword"> double</span><span class="special">&gt;</span><span class="special"> &gt;())</span></tt></pre>
<p>
Notice the use of <tt class="literal">init&lt;...&gt;</tt> and <tt class="literal">optional&lt;...&gt;</tt> to signify the default
(optional arguments).</p>
</div>
<div class="section" lang="en">
<div class="titlepage">
<div><div><h3 class="title">
<a name="python.auto_overloading"></a>Auto-Overloading</h3></div></div>
<div></div>
</div>
<p>
It was mentioned in passing in the previous section that
<tt class="literal">BOOST_PYTHON_FUNCTION_OVERLOADS</tt> and <tt class="literal">BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</tt>
can also be used for overloaded functions and member functions with a
common sequence of initial arguments. Here is an example:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">void</span><span class="identifier"> foo</span><span class="special">()</span><span class="special">
{</span><span class="comment">
/*...*/</span><span class="special">
}</span><span class="keyword">
void</span><span class="identifier"> foo</span><span class="special">(</span><span class="keyword">bool</span><span class="identifier"> a</span><span class="special">)</span><span class="special">
{</span><span class="comment">
/*...*/</span><span class="special">
}</span><span class="keyword">
void</span><span class="identifier"> foo</span><span class="special">(</span><span class="keyword">bool</span><span class="identifier"> a</span><span class="special">,</span><span class="keyword"> int</span><span class="identifier"> b</span><span class="special">)</span><span class="special">
{</span><span class="comment">
/*...*/</span><span class="special">
}</span><span class="keyword">
void</span><span class="identifier"> foo</span><span class="special">(</span><span class="keyword">bool</span><span class="identifier"> a</span><span class="special">,</span><span class="keyword"> int</span><span class="identifier"> b</span><span class="special">,</span><span class="keyword"> char</span><span class="identifier"> c</span><span class="special">)</span><span class="special">
{</span><span class="comment">
/*...*/</span><span class="special">
}</span></tt></pre>
<p>
Like in the previous section, we can generate thin wrappers for these
overloaded functions in one-shot:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">BOOST_PYTHON_FUNCTION_OVERLOADS</span><span class="special">(</span><span class="identifier">foo_overloads</span><span class="special">,</span><span class="identifier"> foo</span><span class="special">,</span><span class="number"> 0</span><span class="special">,</span><span class="number"> 3</span><span class="special">)</span></tt></pre>
<p>
Then...</p>
<pre class="programlisting"><tt class="literal"><span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"foo"</span><span class="special">,</span><span class="identifier"> foo</span><span class="special">,</span><span class="identifier"> foo_overloads</span><span class="special">());</span></tt></pre>
<p>
Notice though that we have a situation now where we have a minimum of zero
(0) arguments and a maximum of 3 arguments.</p>
<a name="auto_overloading.manual_wrapping"></a><h2>
<a name="id425478"></a>Manual Wrapping</h2>
<p>
It is important to emphasize however that <span class="bold"><b>the overloaded functions must
have a common sequence of initial arguments</b></span>. Otherwise, our scheme above
will not work. If this is not the case, we have to wrap our functions
<a href="functions.html#overloading" target="_top">manually</a>.</p>
<p>
Actually, we can mix and match manual wrapping of overloaded functions and
automatic wrapping through <tt class="literal">BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</tt> and
its sister, <tt class="literal">BOOST_PYTHON_FUNCTION_OVERLOADS</tt>. Following up on our example
presented in the section <a href="functions.html#overloading" target="_top">on overloading</a>, since the
first 4 overload functins have a common sequence of initial arguments, we
can use <tt class="literal">BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</tt> to automatically wrap the
first three of the <tt class="literal">def</tt>s and manually wrap just the last. Here's
how we'll do this:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</span><span class="special">(</span><span class="identifier">xf_overloads</span><span class="special">,</span><span class="identifier"> f</span><span class="special">,</span><span class="number"> 1</span><span class="special">,</span><span class="number"> 4</span><span class="special">)</span></tt></pre>
<p>
Create a member function pointers as above for both X::f overloads:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">bool</span><span class="special"> (</span><span class="identifier">X</span><span class="special">::*</span><span class="identifier">fx1</span><span class="special">)(</span><span class="keyword">int</span><span class="special">,</span><span class="keyword"> double</span><span class="special">,</span><span class="keyword"> char</span><span class="special">)</span><span class="special"> =</span><span class="special"> &amp;</span><span class="identifier">X</span><span class="special">::</span><span class="identifier">f</span><span class="special">;</span><span class="keyword">
int</span><span class="special"> (</span><span class="identifier">X</span><span class="special">::*</span><span class="identifier">fx2</span><span class="special">)(</span><span class="keyword">int</span><span class="special">,</span><span class="keyword"> int</span><span class="special">,</span><span class="keyword"> int</span><span class="special">)</span><span class="special"> =</span><span class="special"> &amp;</span><span class="identifier">X</span><span class="special">::</span><span class="identifier">f</span><span class="special">;</span></tt></pre>
<p>
Then...</p>
<pre class="programlisting"><tt class="literal"><span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span><span class="identifier"> fx1</span><span class="special">,</span><span class="identifier"> xf_overloads</span><span class="special">());</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"f"</span><span class="special">,</span><span class="identifier"> fx2</span><span class="special">)</span></tt></pre>
</div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><small>Copyright © 2002-2004 Joel de Guzman, David Abrahams</small></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="exposing.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="object.html"><img src="../images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -0,0 +1,233 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title> Building Hello World</title>
<link rel="stylesheet" href="../boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.65.1">
<link rel="home" href="../index.html" title="Chapter 1. python 1.0">
<link rel="up" href="../index.html" title="Chapter 1. python 1.0">
<link rel="previous" href="../index.html" title="Chapter 1. python 1.0">
<link rel="next" href="exposing.html" title=" Exposing Classes">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%">
<td valign="top"><img alt="boost.png (6897 bytes)" width="277" height="86" src="../../../boost.png"></td>
<td align="center"><a href="../../../index.htm">Home</a></td>
<td align="center"><a href="../libraries.html">Libraries</a></td>
<td align="center"><a href="../../../people/people.htm">People</a></td>
<td align="center"><a href="../../../more/faq.htm">FAQ</a></td>
<td align="center"><a href="../../../more/index.htm">More</a></td>
</table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="../index.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="exposing.html"><img src="../images/next.png" alt="Next"></a>
</div>
<div class="section" lang="en">
<div class="titlepage">
<div><div><h2 class="title" style="clear: both">
<a name="python.hello"></a> Building Hello World</h2></div></div>
<div></div>
</div>
<a name="hello.from_start_to_finish"></a><h2>
<a name="id343708"></a>From Start To Finish</h2>
<p>
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: <span class="bold"><b>bjam</b></span>.</p>
<div class="informaltable"><table class="table">
<colgroup><col></colgroup>
<tbody><tr><td>
<span class="inlinemediaobject"><img src="../images/note.png"></span><span class="bold"><b>Building without bjam</b></span><p></p>
<p></p>
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 <tt class="literal">bjam</tt>.<p></p>
<p></p>
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.
</td></tr></tbody>
</table></div>
<p>
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: <a href="../../../../building.html" target="_top">building.html</a>.
After this brief <span class="emphasis"><em>bjam</em></span> tutorial, we should have built two DLLs:</p>
<div class="itemizedlist"><ul type="disc">
<li>
boost_python.dll
</li>
<li>
hello.pyd
</li>
</ul></div>
<p>
if you are on Windows, and</p>
<div class="itemizedlist"><ul type="disc">
<li>
libboost_python.so
</li>
<li>
hello.so
</li>
</ul></div>
<p>
if you are on Unix.</p>
<p>
The tutorial example can be found in the directory:
<tt class="literal">libs/python/example/tutorial</tt>. There, you can find:</p>
<div class="itemizedlist"><ul type="disc">
<li>
hello.cpp
</li>
<li>
Jamfile
</li>
</ul></div>
<p>
The <tt class="literal">hello.cpp</tt> file is our C++ hello world example. The <tt class="literal">Jamfile</tt> is a
minimalist <span class="emphasis"><em>bjam</em></span> script that builds the DLLs for us.</p>
<p>
Before anything else, you should have the bjam executable in your boost
directory or somewhere in your path such that <tt class="literal">bjam</tt> 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
<a href="http://sourceforge.net/project/showfiles.php?group_id=7586" target="_top">here</a>.</p>
<a name="hello.let_s_jam_"></a><h2>
<a name="id343869"></a>Let's Jam!</h2>
<p><span class="inlinemediaobject"><img src="../images/jam.png"></span></p>
<p>
Here is our minimalist Jamfile:</p>
<pre class="programlisting"><tt class="literal"> 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
&lt;dll&gt;../../build/boost_python # dependencies
;
</tt></pre>
<p>
First, we need to specify our location in the boost project hierarchy.
It so happens that the tutorial example is located in <tt class="literal">/libs/python/example/tutorial</tt>.
Thus:</p>
<pre class="programlisting"><tt class="literal"> subproject libs/python/example/tutorial ;
</tt></pre>
<p>
Then we will include the definitions needed by Python modules:</p>
<pre class="programlisting"><tt class="literal"> SEARCH on python.jam = $(BOOST_BUILD_PATH) ;
include python.jam ;
</tt></pre>
<p>
Finally we declare our <tt class="literal">hello</tt> extension:</p>
<pre class="programlisting"><tt class="literal"> extension hello # Declare a Python extension called hello
: hello.cpp # source
&lt;dll&gt;../../build/boost_python # dependencies
;
</tt></pre>
<a name="hello.running_bjam"></a><h2>
<a name="id343964"></a>Running bjam</h2>
<p><span class="emphasis"><em>bjam</em></span> is run using your operating system's command line interpreter.</p>
<div class="blockquote"><blockquote class="blockquote"><p>Start it up.</p></blockquote></div>
<p>
Make sure that the environment is set so that we can invoke the C++
compiler. With MSVC, that would mean running the <tt class="literal">Vcvars32.bat</tt> batch
file. For instance:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">C</span><span class="special">:\</span><span class="identifier">Program</span><span class="identifier"> Files</span><span class="special">\</span><span class="identifier">Microsoft</span><span class="identifier"> Visual</span><span class="identifier"> Studio</span><span class="special">\</span><span class="identifier">VC98</span><span class="special">\</span><span class="identifier">bin</span><span class="special">\</span><span class="identifier">Vcvars32</span><span class="special">.</span><span class="identifier">bat</span></tt></pre>
<p>
Some environment variables will have to be setup for proper building of our
Python modules. Example:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">set</span><span class="identifier"> PYTHON_ROOT</span><span class="special">=</span><span class="identifier">c</span><span class="special">:/</span><span class="identifier">dev</span><span class="special">/</span><span class="identifier">tools</span><span class="special">/</span><span class="identifier">python</span><span class="identifier">
set</span><span class="identifier"> PYTHON_VERSION</span><span class="special">=</span><span class="number">2.2</span></tt></pre>
<p>
The above assumes that the Python installation is in <tt class="literal">c:/dev/tools/python</tt>
and that we are using Python version 2.2. You'll have to tweak this path
appropriately.</p>
<div class="informaltable"><table class="table">
<colgroup><col></colgroup>
<tbody><tr><td>
<span class="inlinemediaobject"><img src="../images/tip.png"></span> Be sure not to include a third number, e.g. <span class="bold"><b>not</b></span> "2.2.1",
even if that's the version you have.</td></tr></tbody>
</table></div>
<p>
Now we are ready... Be sure to <tt class="literal">cd</tt> to <tt class="literal">libs/python/example/tutorial</tt>
where the tutorial <tt class="literal">"hello.cpp"</tt> and the <tt class="literal">"Jamfile"</tt> is situated.</p>
<p>
Finally:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">bjam</span><span class="special"> -</span><span class="identifier">sTOOLS</span><span class="special">=</span><span class="identifier">msvc</span></tt></pre>
<p>
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
<a href="../../../../../../../tools/build/index.html" target="_top">Building Boost Libraries</a> for
further details.</p>
<p>
It should be building now:</p>
<pre class="programlisting"><tt class="literal"> cd C:\dev\boost\libs\python\example\tutorial
bjam -sTOOLS=msvc
...patience...
...found 1703 targets...
...updating 40 targets...
</tt></pre>
<p>
And so on... Finally:</p>
<pre class="programlisting"><tt class="literal"> 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...
</tt></pre>
<p>
If all is well, you should now have:</p>
<div class="itemizedlist"><ul type="disc">
<li>
boost_python.dll
</li>
<li>
hello.pyd
</li>
</ul></div>
<p>
if you are on Windows, and</p>
<div class="itemizedlist"><ul type="disc">
<li>
libboost_python.so
</li>
<li>
hello.so
</li>
</ul></div>
<p>
if you are on Unix.</p>
<p><tt class="literal">boost_python.dll</tt> can be found somewhere in <tt class="literal">libs\python\build\bin</tt>
while <tt class="literal">hello.pyd</tt> can be found somewhere in
<tt class="literal">libs\python\example\tutorial\bin</tt>. 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.</p>
<p>
You may now fire up Python and run our hello module:</p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="identifier"> import</span><span class="identifier"> hello</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> print</span><span class="identifier"> hello</span><span class="special">.</span><span class="identifier">greet</span><span class="special">()</span><span class="identifier">
hello</span><span class="special">,</span><span class="identifier"> world</span></tt></pre>
<div class="blockquote"><blockquote class="blockquote"><p><span class="bold"><b>There you go... Have fun!</b></span></p></blockquote></div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><small>Copyright © 2002-2004 Joel de Guzman, David Abrahams</small></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="../index.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="exposing.html"><img src="../images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -0,0 +1,131 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Iterators</title>
<link rel="stylesheet" href="../boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.65.1">
<link rel="home" href="../index.html" title="Chapter 1. python 1.0">
<link rel="up" href="../index.html" title="Chapter 1. python 1.0">
<link rel="previous" href="embedding.html" title="Embedding">
<link rel="next" href="exception.html" title=" Exception Translation">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%">
<td valign="top"><img alt="boost.png (6897 bytes)" width="277" height="86" src="../../../boost.png"></td>
<td align="center"><a href="../../../index.htm">Home</a></td>
<td align="center"><a href="../libraries.html">Libraries</a></td>
<td align="center"><a href="../../../people/people.htm">People</a></td>
<td align="center"><a href="../../../more/faq.htm">FAQ</a></td>
<td align="center"><a href="../../../more/index.htm">More</a></td>
</table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="embedding.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="exception.html"><img src="../images/next.png" alt="Next"></a>
</div>
<div class="section" lang="en">
<div class="titlepage">
<div><div><h2 class="title" style="clear: both">
<a name="python.iterators"></a>Iterators</h2></div></div>
<div></div>
</div>
<p>
In C++, and STL in particular, we see iterators everywhere. Python also has
iterators, but these are two very different beasts.</p>
<p><span class="bold"><b>C++ iterators:</b></span></p>
<div class="itemizedlist"><ul type="disc">
<li>
C++ has 5 type categories (random-access, bidirectional, forward, input, output)
</li>
<li>
There are 2 Operation categories: reposition, access
</li>
<li>
A pair of iterators is needed to represent a (first/last) range.
</li>
</ul></div>
<p><span class="bold"><b>Python Iterators:</b></span></p>
<div class="itemizedlist"><ul type="disc">
<li>
1 category (forward)
</li>
<li>
1 operation category (next())
</li>
<li>
Raises StopIteration exception at end
</li>
</ul></div>
<p>
The typical Python iteration protocol: <tt class="literal"><span class="bold"><b>for y in x...</b></span></tt> is as follows:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">iter</span><span class="special"> =</span><span class="identifier"> x</span><span class="special">.</span><span class="identifier">__iter__</span><span class="special">()</span>         #<span class="identifier"> get</span><span class="identifier"> iterator</span><span class="keyword">
try</span><span class="special">:</span><span class="keyword">
while</span><span class="number"> 1</span><span class="special">:</span><span class="identifier">
y</span><span class="special"> =</span><span class="identifier"> iter</span><span class="special">.</span><span class="identifier">next</span><span class="special">()</span>         #<span class="identifier"> get</span><span class="identifier"> each</span><span class="identifier"> item</span><span class="special">
...</span>                     #<span class="identifier"> process</span><span class="identifier"> y</span><span class="identifier">
except</span><span class="identifier"> StopIteration</span><span class="special">:</span><span class="identifier"> pass</span>  #<span class="identifier"> iterator</span><span class="identifier"> exhausted</span></tt></pre>
<p>
Boost.Python provides some mechanisms to make C++ iterators play along
nicely as Python iterators. What we need to do is to produce
appropriate <span class="underline">_iter</span>_ function from C++ iterators that is compatible
with the Python iteration protocol. For example:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">object</span><span class="identifier"> get_iterator</span><span class="special"> =</span><span class="identifier"> iterator</span><span class="special">&lt;</span><span class="identifier">vector</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;</span><span class="special"> &gt;();</span><span class="identifier">
object</span><span class="identifier"> iter</span><span class="special"> =</span><span class="identifier"> get_iterator</span><span class="special">(</span><span class="identifier">v</span><span class="special">);</span><span class="identifier">
object</span><span class="identifier"> first</span><span class="special"> =</span><span class="identifier"> iter</span><span class="special">.</span><span class="identifier">next</span><span class="special">();</span></tt></pre>
<p>
Or for use in class_&lt;&gt;:</p>
<pre class="programlisting"><tt class="literal"><span class="special">.</span><span class="identifier">def</span><span class="special">(</span><span class="string">"__iter__"</span><span class="special">,</span><span class="identifier"> iterator</span><span class="special">&lt;</span><span class="identifier">vector</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;</span><span class="special"> &gt;())</span></tt></pre>
<p><span class="bold"><b>range</b></span></p>
<p>
We can create a Python savvy iterator using the range function:</p>
<div class="itemizedlist"><ul type="disc">
<li>
range(start, finish)
</li>
<li>
range&lt;Policies,Target&gt;(start, finish)
</li>
</ul></div>
<p>
Here, start/finish may be one of:</p>
<div class="itemizedlist"><ul type="disc">
<li>
member data pointers
</li>
<li>
member function pointers
</li>
<li>
adaptable function object (use Target parameter)
</li>
</ul></div>
<p><span class="bold"><b>iterator</b></span></p>
<div class="itemizedlist"><ul type="disc"><li>
iterator&lt;T, Policies&gt;()
</li></ul></div>
<p>
Given a container <tt class="literal">T</tt>, iterator is a shortcut that simply calls <tt class="literal">range</tt>
with &amp;T::begin, &amp;T::end.</p>
<p>
Let's put this into action... Here's an example from some hypothetical
bogon Particle accelerator code:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">f</span><span class="special"> =</span><span class="identifier"> Field</span><span class="special">()</span><span class="keyword">
for</span><span class="identifier"> x</span><span class="identifier"> in</span><span class="identifier"> f</span><span class="special">.</span><span class="identifier">pions</span><span class="special">:</span><span class="identifier">
smash</span><span class="special">(</span><span class="identifier">x</span><span class="special">)</span><span class="keyword">
for</span><span class="identifier"> y</span><span class="identifier"> in</span><span class="identifier"> f</span><span class="special">.</span><span class="identifier">bogons</span><span class="special">:</span><span class="identifier">
count</span><span class="special">(</span><span class="identifier">y</span><span class="special">)</span></tt></pre>
<p>
Now, our C++ Wrapper:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">class_</span><span class="special">&lt;</span><span class="identifier">F</span><span class="special">&gt;(</span><span class="string">"Field"</span><span class="special">)</span><span class="special">
.</span><span class="identifier">property</span><span class="special">(</span><span class="string">"pions"</span><span class="special">,</span><span class="identifier"> range</span><span class="special">(&amp;</span><span class="identifier">F</span><span class="special">::</span><span class="identifier">p_begin</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">F</span><span class="special">::</span><span class="identifier">p_end</span><span class="special">))</span><span class="special">
.</span><span class="identifier">property</span><span class="special">(</span><span class="string">"bogons"</span><span class="special">,</span><span class="identifier"> range</span><span class="special">(&amp;</span><span class="identifier">F</span><span class="special">::</span><span class="identifier">b_begin</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">F</span><span class="special">::</span><span class="identifier">b_end</span><span class="special">));</span></tt></pre>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><small>Copyright © 2002-2004 Joel de Guzman, David Abrahams</small></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="embedding.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="exception.html"><img src="../images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -0,0 +1,273 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title> Object Interface</title>
<link rel="stylesheet" href="../boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.65.1">
<link rel="home" href="../index.html" title="Chapter 1. python 1.0">
<link rel="up" href="../index.html" title="Chapter 1. python 1.0">
<link rel="previous" href="functions.html" title="Functions">
<link rel="next" href="embedding.html" title="Embedding">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%">
<td valign="top"><img alt="boost.png (6897 bytes)" width="277" height="86" src="../../../boost.png"></td>
<td align="center"><a href="../../../index.htm">Home</a></td>
<td align="center"><a href="../libraries.html">Libraries</a></td>
<td align="center"><a href="../../../people/people.htm">People</a></td>
<td align="center"><a href="../../../more/faq.htm">FAQ</a></td>
<td align="center"><a href="../../../more/index.htm">More</a></td>
</table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="functions.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="embedding.html"><img src="../images/next.png" alt="Next"></a>
</div>
<div class="section" lang="en">
<div class="titlepage">
<div><div><h2 class="title" style="clear: both">
<a name="python.object"></a> Object Interface</h2></div></div>
<div></div>
</div>
<div class="toc"><dl>
<dt><span class="section"><a href="object.html#python.basic_interface">Basic Interface</a></span></dt>
<dt><span class="section"><a href="object.html#python.derived_object_types">Derived Object types</a></span></dt>
<dt><span class="section"><a href="object.html#python.extracting_c___objects">Extracting C++ objects</a></span></dt>
<dt><span class="section"><a href="object.html#python.enums">Enums</a></span></dt>
</dl></div>
<p>
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 <tt class="literal">object</tt>. We shall see in
this chapter how to deal with Python objects.</p>
<p>
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++ <tt class="literal">object</tt>s are as close as possible to Python. This
should minimize the learning curve significantly.</p>
<p><span class="inlinemediaobject"><img src="../images/python.png"></span></p>
<div class="section" lang="en">
<div class="titlepage">
<div><div><h3 class="title">
<a name="python.basic_interface"></a>Basic Interface</h3></div></div>
<div></div>
</div>
<p>
Class <tt class="literal">object</tt> wraps <tt class="literal">PyObject*</tt>. All the intricacies of dealing with
<tt class="literal">PyObject</tt>s such as managing reference counting are handled by the
<tt class="literal">object</tt> class. C++ object interoperability is seamless. Boost.Python C++
<tt class="literal">object</tt>s can in fact be explicitly constructed from any C++ object.</p>
<p>
To illustrate, this Python code snippet:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">def</span><span class="identifier"> f</span><span class="special">(</span><span class="identifier">x</span><span class="special">,</span><span class="identifier"> y</span><span class="special">):</span><span class="keyword">
if</span><span class="special"> (</span><span class="identifier">y</span><span class="special"> ==</span><span class="char"> 'foo'</span><span class="special">):</span><span class="identifier">
x</span><span class="special">[</span><span class="number">3</span><span class="special">:</span><span class="number">7</span><span class="special">]</span><span class="special"> =</span><span class="char"> 'bar'</span><span class="keyword">
else</span><span class="special">:</span><span class="identifier">
x</span><span class="special">.</span><span class="identifier">items</span><span class="special"> +=</span><span class="identifier"> y</span><span class="special">(</span><span class="number">3</span><span class="special">,</span><span class="identifier"> x</span><span class="special">)</span><span class="keyword">
return</span><span class="identifier"> x</span><span class="identifier">
def</span><span class="identifier"> getfunc</span><span class="special">():</span><span class="keyword">
return</span><span class="identifier"> f</span><span class="special">;</span></tt></pre>
<p>
Can be rewritten in C++ using Boost.Python facilities this way:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">object</span><span class="identifier"> f</span><span class="special">(</span><span class="identifier">object</span><span class="identifier"> x</span><span class="special">,</span><span class="identifier"> object</span><span class="identifier"> y</span><span class="special">)</span><span class="special"> {</span><span class="keyword">
if</span><span class="special"> (</span><span class="identifier">y</span><span class="special"> ==</span><span class="string"> "foo"</span><span class="special">)</span><span class="identifier">
x</span><span class="special">.</span><span class="identifier">slice</span><span class="special">(</span><span class="number">3</span><span class="special">,</span><span class="number">7</span><span class="special">)</span><span class="special"> =</span><span class="string"> "bar"</span><span class="special">;</span><span class="keyword">
else</span><span class="identifier">
x</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"items"</span><span class="special">)</span><span class="special"> +=</span><span class="identifier"> y</span><span class="special">(</span><span class="number">3</span><span class="special">,</span><span class="identifier"> x</span><span class="special">);</span><span class="keyword">
return</span><span class="identifier"> x</span><span class="special">;</span><span class="special">
}</span><span class="identifier">
object</span><span class="identifier"> getfunc</span><span class="special">()</span><span class="special"> {</span><span class="keyword">
return</span><span class="identifier"> object</span><span class="special">(</span><span class="identifier">f</span><span class="special">);</span><span class="special">
}</span></tt></pre>
<p>
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.</p>
</div>
<div class="section" lang="en">
<div class="titlepage">
<div><div><h3 class="title">
<a name="python.derived_object_types"></a>Derived Object types</h3></div></div>
<div></div>
</div>
<p>
Boost.Python comes with a set of derived <tt class="literal">object</tt> types corresponding to
that of Python's:</p>
<div class="itemizedlist"><ul type="disc">
<li>
list
</li>
<li>
dict
</li>
<li>
tuple
</li>
<li>
str
</li>
<li>
long_
</li>
<li>
enum
</li>
</ul></div>
<p>
These derived <tt class="literal">object</tt> types act like real Python types. For instance:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">str</span><span class="special">(</span><span class="number">1</span><span class="special">)</span><span class="special"> ==&gt;</span><span class="string"> "1"</span></tt></pre>
<p>
Wherever appropriate, a particular derived <tt class="literal">object</tt> has corresponding
Python type's methods. For instance, <tt class="literal">dict</tt> has a <tt class="literal">keys()</tt> method:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">d</span><span class="special">.</span><span class="identifier">keys</span><span class="special">()</span></tt></pre>
<p><tt class="literal">make_tuple</tt> is provided for declaring <span class="emphasis"><em>tuple literals</em></span>. Example:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">make_tuple</span><span class="special">(</span><span class="number">123</span><span class="special">,</span><span class="char"> 'D'</span><span class="special">,</span><span class="string"> "Hello, World"</span><span class="special">,</span><span class="number"> 0.0</span><span class="special">);</span></tt></pre>
<p>
In C++, when Boost.Python <tt class="literal">object</tt>s are used as arguments to functions,
subtype matching is required. For example, when a function <tt class="literal">f</tt>, as
declared below, is wrapped, it will only accept instances of Python's
<tt class="literal">str</tt> type and subtypes.</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">void</span><span class="identifier"> f</span><span class="special">(</span><span class="identifier">str</span><span class="identifier"> name</span><span class="special">)</span><span class="special">
{</span><span class="identifier">
object</span><span class="identifier"> n2</span><span class="special"> =</span><span class="identifier"> name</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"upper"</span><span class="special">)();</span><span class="comment"> // NAME = name.upper()
</span><span class="identifier"> str</span><span class="identifier"> NAME</span><span class="special"> =</span><span class="identifier"> name</span><span class="special">.</span><span class="identifier">upper</span><span class="special">();</span><span class="comment"> // better
</span><span class="identifier"> object</span><span class="identifier"> msg</span><span class="special"> =</span><span class="string"> "%s is bigger than %s"</span><span class="special"> %</span><span class="identifier"> make_tuple</span><span class="special">(</span><span class="identifier">NAME</span><span class="special">,</span><span class="identifier">name</span><span class="special">);</span><span class="special">
}</span></tt></pre>
<p>
In finer detail:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">str</span><span class="identifier"> NAME</span><span class="special"> =</span><span class="identifier"> name</span><span class="special">.</span><span class="identifier">upper</span><span class="special">();</span></tt></pre>
<p>
Illustrates that we provide versions of the str type's methods as C++
member functions.</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">object</span><span class="identifier"> msg</span><span class="special"> =</span><span class="string"> "%s is bigger than %s"</span><span class="special"> %</span><span class="identifier"> make_tuple</span><span class="special">(</span><span class="identifier">NAME</span><span class="special">,</span><span class="identifier">name</span><span class="special">);</span></tt></pre>
<p>
Demonstrates that you can write the C++ equivalent of <tt class="literal">"format" % x,y,z</tt>
in Python, which is useful since there's no easy way to do that in std C++.</p>
<p><span class="inlinemediaobject"><img src="../images/alert.png"></span><span class="bold"><b>Beware</b></span> the common pitfall of forgetting that the constructors
of most of Python's mutable types make copies, just as in Python.</p>
<p>
Python:</p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="identifier"> d</span><span class="special"> =</span><span class="identifier"> dict</span><span class="special">(</span><span class="identifier">x</span><span class="special">.</span><span class="identifier">__dict__</span><span class="special">)</span>     #<span class="identifier"> copies</span><span class="identifier"> x</span><span class="special">.</span><span class="identifier">__dict__</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> d</span><span class="special">[</span><span class="char">'whatever'</span><span class="special">]</span>            #<span class="identifier"> modifies</span><span class="identifier"> the</span><span class="identifier"> copy</span></tt></pre>
<p>
C++:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">dict</span><span class="identifier"> d</span><span class="special">(</span><span class="identifier">x</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"__dict__"</span><span class="special">));</span>  #<span class="identifier"> copies</span><span class="identifier"> x</span><span class="special">.</span><span class="identifier">__dict__</span><span class="identifier">
d</span><span class="special">[</span><span class="char">'whatever'</span><span class="special">]</span><span class="special"> =</span><span class="number"> 3</span><span class="special">;</span>           #<span class="identifier"> modifies</span><span class="identifier"> the</span><span class="identifier"> copy</span></tt></pre>
<a name="derived_object_types.class__lt_t_gt__as_objects"></a><h2>
<a name="id427284"></a>class_&lt;T&gt; as objects</h2>
<p>
Due to the dynamic nature of Boost.Python objects, any <tt class="literal">class_&lt;T&gt;</tt> may
also be one of these types! The following code snippet wraps the class
(type) object.</p>
<p>
We can use this to create wrapped instances. Example:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">object</span><span class="identifier"> vec345</span><span class="special"> =</span><span class="special"> (</span><span class="identifier">
class_</span><span class="special">&lt;</span><span class="identifier">Vec2</span><span class="special">&gt;(</span><span class="string">"Vec2"</span><span class="special">,</span><span class="identifier"> init</span><span class="special">&lt;</span><span class="keyword">double</span><span class="special">,</span><span class="keyword"> double</span><span class="special">&gt;())</span><span class="special">
.</span><span class="identifier">def_readonly</span><span class="special">(</span><span class="string">"length"</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">Point</span><span class="special">::</span><span class="identifier">length</span><span class="special">)</span><span class="special">
.</span><span class="identifier">def_readonly</span><span class="special">(</span><span class="string">"angle"</span><span class="special">,</span><span class="special"> &amp;</span><span class="identifier">Point</span><span class="special">::</span><span class="identifier">angle</span><span class="special">)</span><span class="special">
)(</span><span class="number">3.0</span><span class="special">,</span><span class="number"> 4.0</span><span class="special">);</span><span class="identifier">
assert</span><span class="special">(</span><span class="identifier">vec345</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"length"</span><span class="special">)</span><span class="special"> ==</span><span class="number"> 5.0</span><span class="special">);</span></tt></pre>
</div>
<div class="section" lang="en">
<div class="titlepage">
<div><div><h3 class="title">
<a name="python.extracting_c___objects"></a>Extracting C++ objects</h3></div></div>
<div></div>
</div>
<p>
At some point, we will need to get C++ values out of object instances. This
can be achieved with the <tt class="literal">extract&lt;T&gt;</tt> function. Consider the following:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">double</span><span class="identifier"> x</span><span class="special"> =</span><span class="identifier"> o</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"length"</span><span class="special">);</span><span class="comment"> // compile error
</span></tt></pre>
<p>
In the code above, we got a compiler error because Boost.Python
<tt class="literal">object</tt> can't be implicitly converted to <tt class="literal">double</tt>s. Instead, what
we wanted to do above can be achieved by writing:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">double</span><span class="identifier"> l</span><span class="special"> =</span><span class="identifier"> extract</span><span class="special">&lt;</span><span class="keyword">double</span><span class="special">&gt;(</span><span class="identifier">o</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"length"</span><span class="special">));</span><span class="identifier">
Vec2</span><span class="special">&amp;</span><span class="identifier"> v</span><span class="special"> =</span><span class="identifier"> extract</span><span class="special">&lt;</span><span class="identifier">Vec2</span><span class="special">&amp;&gt;(</span><span class="identifier">o</span><span class="special">);</span><span class="identifier">
assert</span><span class="special">(</span><span class="identifier">l</span><span class="special"> ==</span><span class="identifier"> v</span><span class="special">.</span><span class="identifier">length</span><span class="special">());</span></tt></pre>
<p>
The first line attempts to extract the "length" attribute of the
Boost.Python <tt class="literal">object</tt><tt class="literal">o</tt>. The second line attempts to <span class="emphasis"><em>extract</em></span> the
<tt class="literal">Vec2</tt> object from held by the Boost.Python <tt class="literal">object</tt><tt class="literal">o</tt>.</p>
<p>
Take note that we said "attempt to" above. What if the Boost.Python
<tt class="literal">object</tt><tt class="literal">o</tt> does not really hold a <tt class="literal">Vec2</tt> type? This is certainly
a possibility considering the dynamic nature of Python <tt class="literal">object</tt>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:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">extract</span><span class="special">&lt;</span><span class="identifier">Vec2</span><span class="special">&amp;&gt;</span><span class="identifier"> x</span><span class="special">(</span><span class="identifier">o</span><span class="special">);</span><span class="keyword">
if</span><span class="special"> (</span><span class="identifier">x</span><span class="special">.</span><span class="identifier">check</span><span class="special">())</span><span class="special"> {</span><span class="identifier">
Vec2</span><span class="special">&amp;</span><span class="identifier"> v</span><span class="special"> =</span><span class="identifier"> x</span><span class="special">();</span><span class="special"> ...</span></tt></pre>
<p><span class="inlinemediaobject"><img src="../images/tip.png"></span> The astute reader might have noticed that the <tt class="literal">extract&lt;T&gt;</tt>
facility in fact solves the mutable copying problem:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">dict</span><span class="identifier"> d</span><span class="special"> =</span><span class="identifier"> extract</span><span class="special">&lt;</span><span class="identifier">dict</span><span class="special">&gt;(</span><span class="identifier">x</span><span class="special">.</span><span class="identifier">attr</span><span class="special">(</span><span class="string">"__dict__"</span><span class="special">));</span><span class="identifier">
d</span><span class="special">[</span><span class="char">'whatever'</span><span class="special">]</span><span class="special"> =</span><span class="number"> 3</span><span class="special">;</span>          #<span class="identifier"> modifies</span><span class="identifier"> x</span><span class="special">.</span><span class="identifier">__dict__</span><span class="special"> !</span></tt></pre>
</div>
<div class="section" lang="en">
<div class="titlepage">
<div><div><h3 class="title">
<a name="python.enums"></a>Enums</h3></div></div>
<div></div>
</div>
<p>
Boost.Python has a nifty facility to capture and wrap C++ enums. While
Python has no <tt class="literal">enum</tt> type, we'll often want to expose our C++ enums to
Python as an <tt class="literal">int</tt>. 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:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">enum</span><span class="identifier"> choice</span><span class="special"> {</span><span class="identifier"> red</span><span class="special">,</span><span class="identifier"> blue</span><span class="special"> };</span></tt></pre>
<p>
the construct:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">enum_</span><span class="special">&lt;</span><span class="identifier">choice</span><span class="special">&gt;(</span><span class="string">"choice"</span><span class="special">)</span><span class="special">
.</span><span class="identifier">value</span><span class="special">(</span><span class="string">"red"</span><span class="special">,</span><span class="identifier"> red</span><span class="special">)</span><span class="special">
.</span><span class="identifier">value</span><span class="special">(</span><span class="string">"blue"</span><span class="special">,</span><span class="identifier"> blue</span><span class="special">)</span><span class="special">
;</span></tt></pre>
<p>
can be used to expose to Python. The new enum type is created in the
current <tt class="literal">scope()</tt>, which is usually the current module. The snippet above
creates a Python class derived from Python's <tt class="literal">int</tt> type which is
associated with the C++ type passed as its first parameter.</p>
<div class="informaltable"><table class="table">
<colgroup><col></colgroup>
<tbody><tr><td>
<span class="inlinemediaobject"><img src="../images/note.png"></span><span class="bold"><b>what is a scope?</b></span><p></p>
<p></p>
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 <a href="../../../../v2/scope.html" target="_top">here</a>.</td></tr></tbody>
</table></div>
<p>
You can access those values in Python as</p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="identifier"> my_module</span><span class="special">.</span><span class="identifier">choice</span><span class="special">.</span><span class="identifier">red</span><span class="identifier">
my_module</span><span class="special">.</span><span class="identifier">choice</span><span class="special">.</span><span class="identifier">red</span></tt></pre>
<p>
where my_module is the module where the enum is declared. You can also
create a new scope around a class:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">scope</span><span class="identifier"> in_X</span><span class="special"> =</span><span class="identifier"> class_</span><span class="special">&lt;</span><span class="identifier">X</span><span class="special">&gt;(</span><span class="string">"X"</span><span class="special">)</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="special"> ...</span><span class="special"> )</span><span class="special">
.</span><span class="identifier">def</span><span class="special">(</span><span class="special"> ...</span><span class="special"> )</span><span class="special">
;</span><span class="comment">
// Expose X::nested as X.nested
</span><span class="identifier">enum_</span><span class="special">&lt;</span><span class="identifier">X</span><span class="special">::</span><span class="identifier">nested</span><span class="special">&gt;(</span><span class="string">"nested"</span><span class="special">)</span><span class="special">
.</span><span class="identifier">value</span><span class="special">(</span><span class="string">"red"</span><span class="special">,</span><span class="identifier"> red</span><span class="special">)</span><span class="special">
.</span><span class="identifier">value</span><span class="special">(</span><span class="string">"blue"</span><span class="special">,</span><span class="identifier"> blue</span><span class="special">)</span><span class="special">
;</span></tt></pre>
</div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><small>Copyright © 2002-2004 Joel de Guzman, David Abrahams</small></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="functions.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="embedding.html"><img src="../images/next.png" alt="Next"></a>
</div>
</body>
</html>

View File

@@ -0,0 +1,373 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title> General Techniques</title>
<link rel="stylesheet" href="../boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.65.1">
<link rel="home" href="../index.html" title="Chapter 1. python 1.0">
<link rel="up" href="../index.html" title="Chapter 1. python 1.0">
<link rel="previous" href="exception.html" title=" Exception Translation">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%">
<td valign="top"><img alt="boost.png (6897 bytes)" width="277" height="86" src="../../../boost.png"></td>
<td align="center"><a href="../../../index.htm">Home</a></td>
<td align="center"><a href="../libraries.html">Libraries</a></td>
<td align="center"><a href="../../../people/people.htm">People</a></td>
<td align="center"><a href="../../../more/faq.htm">FAQ</a></td>
<td align="center"><a href="../../../more/index.htm">More</a></td>
</table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="exception.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a>
</div>
<div class="section" lang="en">
<div class="titlepage">
<div><div><h2 class="title" style="clear: both">
<a name="python.techniques"></a> General Techniques</h2></div></div>
<div></div>
</div>
<div class="toc"><dl>
<dt><span class="section"><a href="techniques.html#python.creating_packages">Creating Packages</a></span></dt>
<dt><span class="section"><a href="techniques.html#python.extending_wrapped_objects_in_python">Extending Wrapped Objects in Python</a></span></dt>
<dt><span class="section"><a href="techniques.html#python.reducing_compiling_time">Reducing Compiling Time</a></span></dt>
</dl></div>
<p>
Here are presented some useful techniques that you can use while wrapping code with Boost.Python.</p>
<div class="section" lang="en">
<div class="titlepage">
<div><div><h3 class="title">
<a name="python.creating_packages"></a>Creating Packages</h3></div></div>
<div></div>
</div>
<p>
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
<a href="http://www.python.org/doc/current/tut/node8.html" target="_top">Python Tutorial</a>.</p>
<p>
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.</p>
<p>
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)
<tt class="literal">sounds</tt>. Our library already has a neat C++ namespace hierarchy, like so:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">sounds</span><span class="special">::</span><span class="identifier">core</span><span class="identifier">
sounds</span><span class="special">::</span><span class="identifier">io</span><span class="identifier">
sounds</span><span class="special">::</span><span class="identifier">filters</span></tt></pre>
<p>
We would like to present this same hierarchy to the Python user, allowing him
to write code like this:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">import</span><span class="identifier"> sounds</span><span class="special">.</span><span class="identifier">filters</span><span class="identifier">
sounds</span><span class="special">.</span><span class="identifier">filters</span><span class="special">.</span><span class="identifier">echo</span><span class="special">(...)</span> #<span class="identifier"> echo</span><span class="identifier"> is</span><span class="identifier"> a</span><span class="identifier"> C</span><span class="special">++</span><span class="identifier"> function</span></tt></pre>
<p>
The first step is to write the wrapping code. We have to export each module
separately with Boost.Python, like this:</p>
<pre class="programlisting"><tt class="literal"><span class="comment">/* file core.cpp */</span><span class="identifier">
BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">core</span><span class="special">)</span><span class="special">
{</span><span class="comment">
/* export everything in the sounds::core namespace */</span><span class="special">
...</span><span class="special">
}</span><span class="comment">
/* file io.cpp */</span><span class="identifier">
BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">io</span><span class="special">)</span><span class="special">
{</span><span class="comment">
/* export everything in the sounds::io namespace */</span><span class="special">
...</span><span class="special">
}</span><span class="comment">
/* file filters.cpp */</span><span class="identifier">
BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">filters</span><span class="special">)</span><span class="special">
{</span><span class="comment">
/* export everything in the sounds::filters namespace */</span><span class="special">
...</span><span class="special">
}</span></tt></pre>
<p>
Compiling these files will generate the following Python extensions:
<tt class="literal">core.pyd</tt>, <tt class="literal">io.pyd</tt> and <tt class="literal">filters.pyd</tt>.</p>
<div class="informaltable"><table class="table">
<colgroup><col></colgroup>
<tbody><tr><td>
<span class="inlinemediaobject"><img src="../images/note.png"></span> The extension <tt class="literal">.pyd</tt> is used for python extension modules, which
are just shared libraries. Using the default for your system, like <tt class="literal">.so</tt> for
Unix and <tt class="literal">.dll</tt> for Windows, works just as well.</td></tr></tbody>
</table></div>
<p>
Now, we create this directory structure for our Python package:</p>
<pre class="programlisting"><tt class="literal"> sounds/
<span class="underline">_init</span>_.py
core.pyd
filters.pyd
io.pyd
</tt></pre>
<p>
The file <tt class="literal"><span class="underline">_init</span>_.py</tt> is what tells Python that the directory <tt class="literal">sounds/</tt> is
actually a Python package. It can be a empty file, but can also perform some
magic, that will be shown later.</p>
<p>
Now our package is ready. All the user has to do is put <tt class="literal">sounds</tt> into his
<a href="http://www.python.org/doc/current/tut/node8.html#SECTION008110000000000000000" target="_top">PYTHONPATH</a>
and fire up the interpreter:</p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="identifier"> import</span><span class="identifier"> sounds</span><span class="special">.</span><span class="identifier">io</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> import</span><span class="identifier"> sounds</span><span class="special">.</span><span class="identifier">filters</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> sound</span><span class="special"> =</span><span class="identifier"> sounds</span><span class="special">.</span><span class="identifier">io</span><span class="special">.</span><span class="identifier">open</span><span class="special">(</span><span class="char">'file.mp3'</span><span class="special">)</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> new_sound</span><span class="special"> =</span><span class="identifier"> sounds</span><span class="special">.</span><span class="identifier">filters</span><span class="special">.</span><span class="identifier">echo</span><span class="special">(</span><span class="identifier">sound</span><span class="special">,</span><span class="number"> 1.0</span><span class="special">)</span></tt></pre>
<p>
Nice heh?</p>
<p>
This is the simplest way to create hierarchies of packages, but it is not very
flexible. What if we want to add a <span class="emphasis"><em>pure</em></span> 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.</p>
<p>
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:</p>
<pre class="programlisting"><tt class="literal"><span class="comment">/* file core.cpp */</span><span class="identifier">
BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">_core</span><span class="special">)</span><span class="special">
{</span><span class="special">
...</span><span class="comment">
/* export everything in the sounds::core namespace */</span><span class="special">
}</span></tt></pre>
<p>
Note that we added an underscore to the module name. The filename will have to
be changed to <tt class="literal">_core.pyd</tt> as well, and we do the same to the other extension modules.
Now, we change our package hierarchy like so:</p>
<pre class="programlisting"><tt class="literal"> sounds/
<span class="underline">_init</span>_.py
core/
<span class="underline">_init</span>_.py
_core.pyd
filters/
<span class="underline">_init</span>_.py
_filters.pyd
io/
<span class="underline">_init</span>_.py
_io.pyd
</tt></pre>
<p>
Note that we created a directory for each extension module, and added a
<span class="underline">_init</span>_.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:</p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="identifier"> import</span><span class="identifier"> sounds</span><span class="special">.</span><span class="identifier">core</span><span class="special">.</span><span class="identifier">_core</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> sounds</span><span class="special">.</span><span class="identifier">core</span><span class="special">.</span><span class="identifier">_core</span><span class="special">.</span><span class="identifier">foo</span><span class="special">(...)</span></tt></pre>
<p>
which is not what we want. But here enters the <tt class="literal"><span class="underline">_init</span>_.py</tt> magic: everything
that is brought to the <tt class="literal"><span class="underline">_init</span>_.py</tt> namespace can be accessed directly by the
user. So, all we have to do is bring the entire namespace from <tt class="literal">_core.pyd</tt>
to <tt class="literal">core/<span class="underline">_init</span><span class="underline">.py]. So add this line of code to [^sounds/core/</span><span class="underline">init</span>_.py</tt>:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">from</span><span class="identifier"> _core</span><span class="identifier"> import</span><span class="special"> *</span></tt></pre>
<p>
We do the same for the other packages. Now the user accesses the functions and
classes in the extension modules like before:</p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="identifier"> import</span><span class="identifier"> sounds</span><span class="special">.</span><span class="identifier">filters</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> sounds</span><span class="special">.</span><span class="identifier">filters</span><span class="special">.</span><span class="identifier">echo</span><span class="special">(...)</span></tt></pre>
<p>
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 <span class="emphasis"><em>pure</em></span> Python function,
<tt class="literal">echo_noise</tt>, to the <tt class="literal">filters</tt> package. This function applies both the
<tt class="literal">echo</tt> and <tt class="literal">noise</tt> filters in sequence in the given <tt class="literal">sound</tt> object. We
create a file named <tt class="literal">sounds/filters/echo_noise.py</tt> and code our function:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">import</span><span class="identifier"> _filters</span><span class="identifier">
def</span><span class="identifier"> echo_noise</span><span class="special">(</span><span class="identifier">sound</span><span class="special">):</span><span class="identifier">
s</span><span class="special"> =</span><span class="identifier"> _filters</span><span class="special">.</span><span class="identifier">echo</span><span class="special">(</span><span class="identifier">sound</span><span class="special">)</span><span class="identifier">
s</span><span class="special"> =</span><span class="identifier"> _filters</span><span class="special">.</span><span class="identifier">noise</span><span class="special">(</span><span class="identifier">sound</span><span class="special">)</span><span class="keyword">
return</span><span class="identifier"> s</span></tt></pre>
<p>
Next, we add this line to <tt class="literal">sounds<span class="emphasis"><em>filters</em></span><span class="underline">_init</span>_.py</tt>:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">from</span><span class="identifier"> echo_noise</span><span class="identifier"> import</span><span class="identifier"> echo_noise</span></tt></pre>
<p>
And that's it. The user now accesses this function like any other function
from the <tt class="literal">filters</tt> package:</p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="identifier"> import</span><span class="identifier"> sounds</span><span class="special">.</span><span class="identifier">filters</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> sounds</span><span class="special">.</span><span class="identifier">filters</span><span class="special">.</span><span class="identifier">echo_noise</span><span class="special">(...)</span></tt></pre>
</div>
<div class="section" lang="en">
<div class="titlepage">
<div><div><h3 class="title">
<a name="python.extending_wrapped_objects_in_python"></a>Extending Wrapped Objects in Python</h3></div></div>
<div></div>
</div>
<p>
Thanks to Python's flexibility, you can easily add new methods to a class,
even after it was already created:</p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="keyword"> class</span><span class="identifier"> C</span><span class="special">(</span><span class="identifier">object</span><span class="special">):</span><span class="identifier"> pass</span><span class="special">
&gt;&gt;&gt;</span><span class="special">
&gt;&gt;&gt;</span> #<span class="identifier"> a</span><span class="identifier"> regular</span><span class="identifier"> function</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> def</span><span class="identifier"> C_str</span><span class="special">(</span><span class="identifier">self</span><span class="special">):</span><span class="keyword"> return</span><span class="char"> 'A C instance!'</span><span class="special">
&gt;&gt;&gt;</span><span class="special">
&gt;&gt;&gt;</span> #<span class="identifier"> now</span><span class="identifier"> we</span><span class="identifier"> turn</span><span class="identifier"> it</span><span class="identifier"> in</span><span class="identifier"> a</span><span class="identifier"> member</span><span class="identifier"> function</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> C</span><span class="special">.</span><span class="identifier">__str__</span><span class="special"> =</span><span class="identifier"> C_str</span><span class="special">
&gt;&gt;&gt;</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> c</span><span class="special"> =</span><span class="identifier"> C</span><span class="special">()</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> print</span><span class="identifier"> c</span><span class="identifier">
A</span><span class="identifier"> C</span><span class="identifier"> instance</span><span class="special">!</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> C_str</span><span class="special">(</span><span class="identifier">c</span><span class="special">)</span><span class="identifier">
A</span><span class="identifier"> C</span><span class="identifier"> instance</span><span class="special">!</span></tt></pre>
<p>
Yes, Python rox. <span class="inlinemediaobject"><img src="../images/smiley.png"></span></p>
<p>
We can do the same with classes that were wrapped with Boost.Python. Suppose
we have a class <tt class="literal">point</tt> in C++:</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">class</span><span class="identifier"> point</span><span class="special"> {...};</span><span class="identifier">
BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">_geom</span><span class="special">)</span><span class="special">
{</span><span class="identifier">
class_</span><span class="special">&lt;</span><span class="identifier">point</span><span class="special">&gt;(</span><span class="string">"point"</span><span class="special">)...;</span><span class="special">
}</span></tt></pre>
<p>
If we are using the technique from the previous session,
<a href="techniques.html#creating_packages" target="_top">Creating Packages</a>, we can code directly
into <tt class="literal">geom/<span class="underline">_init</span>_.py</tt>:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">from</span><span class="identifier"> _geom</span><span class="identifier"> import</span><span class="special"> *</span>
#<span class="identifier"> a</span><span class="identifier"> regular</span><span class="identifier"> function</span><span class="identifier">
def</span><span class="identifier"> point_str</span><span class="special">(</span><span class="identifier">self</span><span class="special">):</span><span class="keyword">
return</span><span class="identifier"> str</span><span class="special">((</span><span class="identifier">self</span><span class="special">.</span><span class="identifier">x</span><span class="special">,</span><span class="identifier"> self</span><span class="special">.</span><span class="identifier">y</span><span class="special">))</span>
#<span class="identifier"> now</span><span class="identifier"> we</span><span class="identifier"> turn</span><span class="identifier"> it</span><span class="identifier"> into</span><span class="identifier"> a</span><span class="identifier"> member</span><span class="identifier"> function</span><span class="identifier">
point</span><span class="special">.</span><span class="identifier">__str__</span><span class="special"> =</span><span class="identifier"> point_str</span></tt></pre>
<p><span class="bold"><b>All</b></span> point instances created from C++ will also have this member function!
This technique has several advantages:</p>
<div class="itemizedlist"><ul type="disc">
<li>
Cut down compile times to zero for these additional functions
</li>
<li>
Reduce the memory footprint to virtually zero
</li>
<li>
Minimize the need to recompile
</li>
<li>
Rapid prototyping (you can move the code to C++ if required without changing the interface)
</li>
</ul></div>
<p>
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.</p>
<pre class="programlisting"><tt class="literal">
#<span class="identifier"> The</span><span class="identifier"> one</span><span class="identifier"> Boost</span><span class="special">.</span><span class="identifier">Python</span><span class="identifier"> uses</span><span class="keyword"> for</span><span class="identifier"> all</span><span class="identifier"> wrapped</span><span class="identifier"> classes</span><span class="special">.</span>
#<span class="identifier"> You</span><span class="identifier"> can</span><span class="identifier"> use</span><span class="identifier"> here</span><span class="identifier"> any</span><span class="keyword"> class</span><span class="identifier"> exported</span><span class="identifier"> by</span><span class="identifier"> Boost</span><span class="identifier"> instead</span><span class="identifier"> of</span><span class="string"> "point"</span><span class="identifier">
BoostPythonMetaclass</span><span class="special"> =</span><span class="identifier"> point</span><span class="special">.</span><span class="identifier">__class__</span><span class="keyword">
class</span><span class="identifier"> injector</span><span class="special">(</span><span class="identifier">object</span><span class="special">):</span><span class="keyword">
class</span><span class="identifier"> __metaclass__</span><span class="special">(</span><span class="identifier">BoostPythonMetaclass</span><span class="special">):</span><span class="identifier">
def</span><span class="identifier"> __init__</span><span class="special">(</span><span class="identifier">self</span><span class="special">,</span><span class="identifier"> name</span><span class="special">,</span><span class="identifier"> bases</span><span class="special">,</span><span class="identifier"> dict</span><span class="special">):</span><span class="keyword">
for</span><span class="identifier"> b</span><span class="identifier"> in</span><span class="identifier"> bases</span><span class="special">:</span><span class="keyword">
if</span><span class="identifier"> type</span><span class="special">(</span><span class="identifier">b</span><span class="special">)</span><span class="keyword"> not</span><span class="identifier"> in</span><span class="special"> (</span><span class="identifier">self</span><span class="special">,</span><span class="identifier"> type</span><span class="special">):</span><span class="keyword">
for</span><span class="identifier"> k</span><span class="special">,</span><span class="identifier">v</span><span class="identifier"> in</span><span class="identifier"> dict</span><span class="special">.</span><span class="identifier">items</span><span class="special">():</span><span class="identifier">
setattr</span><span class="special">(</span><span class="identifier">b</span><span class="special">,</span><span class="identifier">k</span><span class="special">,</span><span class="identifier">v</span><span class="special">)</span><span class="keyword">
return</span><span class="identifier"> type</span><span class="special">.</span><span class="identifier">__init__</span><span class="special">(</span><span class="identifier">self</span><span class="special">,</span><span class="identifier"> name</span><span class="special">,</span><span class="identifier"> bases</span><span class="special">,</span><span class="identifier"> dict</span><span class="special">)</span>
#<span class="identifier"> inject</span><span class="identifier"> some</span><span class="identifier"> methods</span><span class="identifier"> in</span><span class="identifier"> the</span><span class="identifier"> point</span><span class="identifier"> foo</span><span class="keyword">
class</span><span class="identifier"> more_point</span><span class="special">(</span><span class="identifier">injector</span><span class="special">,</span><span class="identifier"> point</span><span class="special">):</span><span class="identifier">
def</span><span class="identifier"> __repr__</span><span class="special">(</span><span class="identifier">self</span><span class="special">):</span><span class="keyword">
return</span><span class="char"> 'Point(x=%s, y=%s)'</span><span class="special"> %</span><span class="special"> (</span><span class="identifier">self</span><span class="special">.</span><span class="identifier">x</span><span class="special">,</span><span class="identifier"> self</span><span class="special">.</span><span class="identifier">y</span><span class="special">)</span><span class="identifier">
def</span><span class="identifier"> foo</span><span class="special">(</span><span class="identifier">self</span><span class="special">):</span><span class="identifier">
print</span><span class="char"> 'foo!'</span></tt></pre>
<p>
Now let's see how it got:</p>
<pre class="programlisting"><tt class="literal"><span class="special">&gt;&gt;&gt;</span><span class="identifier"> print</span><span class="identifier"> point</span><span class="special">()</span><span class="identifier">
Point</span><span class="special">(</span><span class="identifier">x</span><span class="special">=</span><span class="number">10</span><span class="special">,</span><span class="identifier"> y</span><span class="special">=</span><span class="number">10</span><span class="special">)</span><span class="special">
&gt;&gt;&gt;</span><span class="identifier"> point</span><span class="special">().</span><span class="identifier">foo</span><span class="special">()</span><span class="identifier">
foo</span><span class="special">!</span></tt></pre>
<p>
Another useful idea is to replace constructors with factory functions:</p>
<pre class="programlisting"><tt class="literal"><span class="identifier">_point</span><span class="special"> =</span><span class="identifier"> point</span><span class="identifier">
def</span><span class="identifier"> point</span><span class="special">(</span><span class="identifier">x</span><span class="special">=</span><span class="number">0</span><span class="special">,</span><span class="identifier"> y</span><span class="special">=</span><span class="number">0</span><span class="special">):</span><span class="keyword">
return</span><span class="identifier"> _point</span><span class="special">(</span><span class="identifier">x</span><span class="special">,</span><span class="identifier"> y</span><span class="special">)</span></tt></pre>
<p>
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.</p>
</div>
<div class="section" lang="en">
<div class="titlepage">
<div><div><h3 class="title">
<a name="python.reducing_compiling_time"></a>Reducing Compiling Time</h3></div></div>
<div></div>
</div>
<p>
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:</p>
<pre class="programlisting"><tt class="literal"><span class="comment">/* file point.cpp */</span><span class="preprocessor">
#include</span><span class="special"> &lt;</span><span class="identifier">point</span><span class="special">.</span><span class="identifier">h</span><span class="special">&gt;</span><span class="preprocessor">
#include</span><span class="special"> &lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">python</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span><span class="keyword">
void</span><span class="identifier"> export_point</span><span class="special">()</span><span class="special">
{</span><span class="identifier">
class_</span><span class="special">&lt;</span><span class="identifier">point</span><span class="special">&gt;(</span><span class="string">"point"</span><span class="special">)...;</span><span class="special">
}</span><span class="comment">
/* file triangle.cpp */</span><span class="preprocessor">
#include</span><span class="special"> &lt;</span><span class="identifier">triangle</span><span class="special">.</span><span class="identifier">h</span><span class="special">&gt;</span><span class="preprocessor">
#include</span><span class="special"> &lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">python</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span><span class="keyword">
void</span><span class="identifier"> export_triangle</span><span class="special">()</span><span class="special">
{</span><span class="identifier">
class_</span><span class="special">&lt;</span><span class="identifier">triangle</span><span class="special">&gt;(</span><span class="string">"triangle"</span><span class="special">)...;</span><span class="special">
}</span></tt></pre>
<p>
Now you create a file <tt class="literal">main.cpp</tt>, which contains the <tt class="literal">BOOST_PYTHON_MODULE</tt>
macro, and call the various export functions inside it.</p>
<pre class="programlisting"><tt class="literal"><span class="keyword">void</span><span class="identifier"> export_point</span><span class="special">();</span><span class="keyword">
void</span><span class="identifier"> export_triangle</span><span class="special">();</span><span class="identifier">
BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">_geom</span><span class="special">)</span><span class="special">
{</span><span class="identifier">
export_point</span><span class="special">();</span><span class="identifier">
export_triangle</span><span class="special">();</span><span class="special">
}</span></tt></pre>
<p>
Compiling and linking together all this files produces the same result as the
usual approach:</p>
<pre class="programlisting"><tt class="literal"><span class="preprocessor">#include</span><span class="special"> &lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">python</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span><span class="preprocessor">
#include</span><span class="special"> &lt;</span><span class="identifier">point</span><span class="special">.</span><span class="identifier">h</span><span class="special">&gt;</span><span class="preprocessor">
#include</span><span class="special"> &lt;</span><span class="identifier">triangle</span><span class="special">.</span><span class="identifier">h</span><span class="special">&gt;</span><span class="identifier">
BOOST_PYTHON_MODULE</span><span class="special">(</span><span class="identifier">_geom</span><span class="special">)</span><span class="special">
{</span><span class="identifier">
class_</span><span class="special">&lt;</span><span class="identifier">point</span><span class="special">&gt;(</span><span class="string">"point"</span><span class="special">)...;</span><span class="identifier">
class_</span><span class="special">&lt;</span><span class="identifier">triangle</span><span class="special">&gt;(</span><span class="string">"triangle"</span><span class="special">)...;</span><span class="special">
}</span></tt></pre>
<p>
but the memory is kept under control.</p>
<p>
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.</p>
<div class="informaltable"><table class="table">
<colgroup><col></colgroup>
<tbody><tr><td>
<span class="inlinemediaobject"><img src="../images/note.png"></span> If you're exporting your classes with <a href="../../../../../pyste/index.html" target="_top">Pyste</a>,
take a look at the <tt class="literal">--multiple</tt> option, that generates the wrappers in
various files as demonstrated here.</td></tr></tbody>
</table></div>
<div class="informaltable"><table class="table">
<colgroup><col></colgroup>
<tbody><tr><td>
<span class="inlinemediaobject"><img src="../images/note.png"></span> This method is useful too if you are getting the error message
<span class="emphasis"><em>"fatal error C1204:Compiler limit:internal structure overflow"</em></span> when compiling
a large source file, as explained in the <a href="../../../../v2/faq.html#c1204" target="_top">FAQ</a>.</td></tr></tbody>
</table></div>
</div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><small>Copyright © 2002-2004 Joel de Guzman, David Abrahams</small></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="exception.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a>
</div>
</body>
</html>

View File

@@ -1,22 +1,28 @@
[library Boost Python
[library python
[version 1.0]
[authors Joel de Guzman, David Abrahams]
[authors [de Guzman, Joel], [Abrahams, David]]
[copyright 2002 2003 2004 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.gif]]
[def __alert__ [$images/alert.gif]]
[def __detail__ [$images/lens.gif]]
[def __tip__ [$images/bulb.gif]]
[def :-) [$images/smiley.gif]]
[def __note__ [$../images/note.png]]
[def __alert__ [$../images/alert.png]]
[def __tip__ [$../images/tip.png]]
[def :-) [$../images/smiley.png]]
[beginpage QuickStart]
[section QuickStart]
The Boost Python Library is a framework for interfacing Python and
C++. It allows you to quickly and seamlessly expose C++ classes
@@ -58,8 +64,8 @@ resulting DLL is now visible to Python. Here's a sample Python session:
[:['[*Next stop... Building your Hello World module from start to finish...]]]
[endpage]
[beginpage:hello Building Hello World]
[endsect]
[section:hello Building Hello World]
[h2 From Start To Finish]
@@ -68,21 +74,19 @@ 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.
[blurb __note__ [*Building without bjam]\n\n
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].\n\n
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].
building Boost.Python, check out: [@../../../../building.html building.html].
After this brief ['bjam] tutorial, we should have built two DLLs:
* boost_python.dll
@@ -107,13 +111,11 @@ 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].
platforms. The complete list of Bjam executables can be found
[@http://sourceforge.net/project/showfiles.php?group_id=7586 here].
[h2 Let's Jam!]
[$images/jam.png]
[$../images/jam.png]
Here is our minimalist Jamfile:
@@ -173,8 +175,10 @@ Python modules. Example:
The above assumes that the Python installation is in [^c:/dev/tools/python]
and that we are using Python version 2.2. You'll have to tweak this path
appropriately. __note__ Be sure not to include a third number, e.g. [*not] "2.2.1",
even if that's the version you have.
appropriately.
[blurb __tip__ Be sure not to include a third number, e.g. [*not] "2.2.1",
even if that's the version you have.]
Now we are ready... Be sure to [^cd] to [^libs/python/example/tutorial]
where the tutorial [^"hello.cpp"] and the [^"Jamfile"] is situated.
@@ -185,7 +189,7 @@ Finally:
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
[@../../../../../../../tools/build/index.html Building Boost Libraries] for
further details.
It should be building now:
@@ -240,8 +244,8 @@ You may now fire up Python and run our hello module:
[:[*There you go... Have fun!]]
[endpage]
[beginpage:exposing Exposing Classes]
[endsect]
[section:exposing Exposing Classes]
Now let's expose a C++ class to Python.
@@ -278,7 +282,7 @@ may use our class [^World] in Python. Here's a sample Python session:
>>> planet.greet()
'howdy'
[beginpage Constructors]
[section Constructors]
Our previous example didn't have any explicit constructors.
Since [^World] is declared as a plain struct, it has an implicit default
@@ -336,8 +340,8 @@ all, we may use [^no_init] instead:
This actually adds an [^__init__] method which always raises a
Python RuntimeError exception.
[endpage]
[beginpage Class Data Members]
[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
@@ -375,8 +379,8 @@ as [*read-write].
AttributeError: can't set attribute
]
[endpage]
[beginpage Class Properties]
[endsect]
[section Class Properties]
In C++, classes with public data members are usually frowned
upon. Well designed classes that take advantage of encapsulation hide
@@ -414,8 +418,8 @@ since the [^rovalue] setter member function is not passed in:
.add_property("rovalue", &Num::get)
[endpage]
[beginpage Inheritance]
[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
@@ -464,14 +468,14 @@ 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.html call policies] later.
Boost.Python [@functions.html#python.call_policies call policies] later.
// Tell Python to take ownership of factory's result
def("factory", factory,
return_value_policy<manage_new_object>());
[endpage]
[beginpage Class Virtual Functions]
[endsect]
[section Class Virtual Functions]
In this section, we shall learn how to make functions behave
polymorphically through virtual functions. Continuing our example, let us
@@ -512,7 +516,7 @@ need to create a class wrapper:
PyObject* self;
};
[blurb __detail__ [*member function and methods][br][br] Python, like
[blurb __note__ [*member function and methods]\n\n Python, like
many object oriented languages uses the term [*methods]. Methods
correspond roughly to C++'s [*member functions]]
@@ -521,17 +525,17 @@ 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]]
[blurb __note__ [*Why do we need BaseWrap?]\n\n]
['You may ask], "Why do we need the [^BaseWrap] derived class? This could
have been designed so that everything gets done right inside of
Base."[br][br]
Base."\n\n
One of the goals of Boost.Python is to be minimally intrusive on an
existing C++ design. In principle, it should be possible to expose the
interface for a 3rd party library without changing it. To unintrusively
hook into the virtual functions so that a Python override may be called, we
must use a derived class.[br][br]
must use a derived class.\n\n
Note however that you don't need to do this to get methods overridden
in Python to behave virtually when called ['from] [*Python]. The only
@@ -560,8 +564,8 @@ 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.
[endpage]
[beginpage Deriving a Python Class]
[endsect]
[section Deriving a Python Class]
Continuing, we can derive from our base class Base in Python and override
the virtual function in Python. Before we can do that, we have to set up
@@ -607,10 +611,10 @@ Here's what's happening:
# [^call_method<int>(self, "f");] dispatches the call back to Python.
# [^def f(self): return 42] is finally called.
[endpage]
[beginpage Virtual Functions with Default Implementations]
[endsect]
[section Virtual Functions with Default Implementations]
Recall that in the [@class_virtual_functions.html previous section], we
Recall that in the [@exposing.html#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:
@@ -681,8 +685,8 @@ Calling [^call_f], passing in a [^derived] object:
>>> call_f(derived)
42
[endpage]
[beginpage Class Operators/Special Functions]
[endsect]
[section Class Operators/Special Functions]
[h2 Python Operators]
@@ -745,14 +749,14 @@ that correspond to these Python ['special functions]. Example:
Need we say more?
[blurb __detail__ What is the business of [^operator<<] [^.def(str(self))]?
[blurb __note__ 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)).]
[endpage]
[endpage] [/ Exposing Classes ]
[endsect]
[endsect] [/ Exposing Classes ]
[beginpage Functions]
[section 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
@@ -790,7 +794,7 @@ But before you do, you might want to fire up Python 2.2 or later and type
Namespaces are one honking great idea -- let's do more of those!
]
[beginpage Call Policies]
[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
@@ -914,23 +918,23 @@ or more policies can be composed by chaining. Here's the general syntax:
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].
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<T> with T one of:][br]
* [*reference_existing_object][br]naive (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
* [*with_custodian_and_ward]\n Ties lifetimes of the arguments
* [*with_custodian_and_ward_postcall]\n Ties lifetimes of the arguments and results
* [*return_internal_reference]\n Ties lifetime of one argument to that of result
* [*return_value_policy<T> with T one of:]\n
* [*reference_existing_object]\nnaive (dangerous) approach
* [*copy_const_reference]\nBoost.Python v1 approach
* [*copy_non_const_reference]\n
* [*manage_new_object]\n 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]]
[blurb :-) [*Remember the Zen, Luke:]\n\n
"Explicit is better than implicit"\n
"In the face of ambiguity, refuse the temptation to guess"\n]
[endpage]
[beginpage Overloading]
[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
@@ -976,8 +980,8 @@ With these in hand, we can proceed to define and wrap this for Python:
.def("f", fx3)
.def("f", fx4)
[endpage]
[beginpage Default Arguments]
[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
@@ -996,7 +1000,7 @@ 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
wrapping as outlined in the [@functions.html#overloading previous section], or
writing thin wrappers:
// write "thin wrappers"
@@ -1069,7 +1073,7 @@ fourth macro argument). The thin wrappers are all enclosed in a class named
.def("wack_em", &george::wack_em, george_overloads());
See the [@../../v2/overloads.html#BOOST_PYTHON_FUNCTION_OVERLOADS-spec overloads reference]
See the [@../../../../v2/overloads.html#BOOST_PYTHON_FUNCTION_OVERLOADS-spec overloads reference]
for details.
[h2 init and optional]
@@ -1091,8 +1095,8 @@ You can easily add this constructor to Boost.Python in one shot:
Notice the use of [^init<...>] and [^optional<...>] to signify the default
(optional arguments).
[endpage]
[beginpage Auto-Overloading]
[endsect]
[section Auto-Overloading]
It was mentioned in passing in the previous section that
[^BOOST_PYTHON_FUNCTION_OVERLOADS] and [^BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS]
@@ -1136,12 +1140,12 @@ Notice though that we have a situation now where we have a minimum of zero
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].
[@functions.html#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 [@overloading.html on overloading], since the
presented in the section [@functions.html#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
@@ -1159,10 +1163,10 @@ Then...
.def("f", fx1, xf_overloads());
.def("f", fx2)
[endpage]
[endpage] [/ Functions ]
[endsect]
[endsect] [/ Functions ]
[beginpage:object Object Interface]
[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.,
@@ -1175,9 +1179,9 @@ bidirectional mapping between C++ and Python while maintaining the Python
feel. Boost.Python C++ [^object]s are as close as possible to Python. This
should minimize the learning curve significantly.
[$images/python.png]
[$../images/python.png]
[beginpage Basic Interface]
[section Basic Interface]
Class [^object] wraps [^PyObject*]. All the intricacies of dealing with
[^PyObject]s such as managing reference counting are handled by the
@@ -1213,8 +1217,8 @@ 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.
[endpage]
[beginpage Derived Object types]
[endsect]
[section Derived Object types]
Boost.Python comes with a set of derived [^object] types corresponding to
that of Python's:
@@ -1292,8 +1296,8 @@ We can use this to create wrapped instances. Example:
assert(vec345.attr("length") == 5.0);
[endpage]
[beginpage Extracting C++ objects]
[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:
@@ -1330,8 +1334,8 @@ facility in fact solves the mutable copying problem:
d['whatever'] = 3; # modifies x.__dict__ !
[endpage]
[beginpage Enums]
[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
@@ -1354,10 +1358,10 @@ 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
[blurb __note__ [*what is a scope?]\n\n 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].]
attributes. Details can be found [@../../../../v2/scope.html here].]
You can access those values in Python as
@@ -1392,10 +1396,10 @@ create a new scope around a class:
[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]]
[endpage]
[endpage] [/ Object Interface]
[endsect]
[endsect] [/ Object Interface]
[beginpage Embedding]
[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
@@ -1418,7 +1422,7 @@ Boost.Python's static link library comes in two variants. Both are located
in Boost's [^/libs/python/build/bin-stage] subdirectory. On Windows, the
variants are called [^boost_python.lib] (for release builds) and
[^boost_python_debug.lib] (for debugging). If you can't find the libraries,
you probably haven't built Boost.Python yet. See [@../../building.html
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
@@ -1453,11 +1457,11 @@ 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>][br][br]
# '''#include''' [^<boost/python.hpp>]\n\n
# Call Py_Initialize() to start the interpreter and create the [^__main__] module.[br][br]
# Call Py_Initialize() to start the interpreter and create the [^__main__] module.\n\n
# Call other Python C API routines to use the interpreter.[br][br]
# Call other Python C API routines to use the interpreter.\n\n
# Call Py_Finalize() to stop the interpreter and release its resources.
@@ -1465,7 +1469,7 @@ steps:
[:['[*Now that we can embed the interpreter in our programs, lets see how to put it to use...]]]
[beginpage Using the interpreter]
[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.
@@ -1474,7 +1478,7 @@ 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.
[@../../../../v2/object.html object] class templates to automate the process.
[h2 Reference-counting handles and objects]
@@ -1486,7 +1490,7 @@ 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
[@../../../../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
@@ -1502,8 +1506,8 @@ 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]
[blurb __note__ [*Handle is a class ['template], so why haven't we been using any template parameters?]\n
\n
[^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>].
]
@@ -1576,7 +1580,7 @@ you want to be a Dr. Frankenstein, always wrap [^PyObject*]s in [^handle]s.
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
above, and in the [@object.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:
@@ -1618,7 +1622,11 @@ 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]:
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
{
@@ -1637,7 +1645,14 @@ If an exception occurs in the execution of some Python code, the PyRun_String fu
// 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]:
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)
{
@@ -1652,9 +1667,12 @@ The [^error_already_set] exception class doesn't carry any information in itself
}
}
(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].)
(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:
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"
@@ -1667,10 +1685,10 @@ If you'd rather not have [^handle] throw a C++ exception when it is constructed,
else
// everything went okay, it's safe to use the result
[endpage]
[endpage] [/ Embedding]
[endsect]
[endsect] [/ Embedding]
[beginpage Iterators]
[section Iterators]
In C++, and STL in particular, we see iterators everywhere. Python also has
iterators, but these are two very different beasts.
@@ -1744,8 +1762,8 @@ Now, our C++ Wrapper:
.property("pions", range(&F::p_begin, &F::p_end))
.property("bogons", range(&F::b_begin, &F::b_end));
[endpage]
[beginpage:exception Exception Translation]
[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
@@ -1765,12 +1783,12 @@ Users may provide custom translation. Here's an example:
PodBayDoorException>(translator);
...
[endpage]
[beginpage:techniques General Techniques]
[endsect]
[section:techniques General Techniques]
Here are presented some useful techniques that you can use while wrapping code with Boost.Python.
[beginpage Creating Packages]
[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
@@ -1841,7 +1859,8 @@ 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:
[@http://www.python.org/doc/current/tut/node8.html#SECTION008110000000000000000 PYTHONPATH]
and fire up the interpreter:
>>> import sounds.io
>>> import sounds.filters
@@ -1928,8 +1947,8 @@ from the [^filters] package:
>>> import sounds.filters
>>> sounds.filters.echo_noise(...)
[endpage]
[beginpage Extending Wrapped Objects in Python]
[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:
@@ -1961,7 +1980,8 @@ we have a class [^point] in C++:
}
If we are using the technique from the previous session,
[@creating_packages.html Creating Packages], we can code directly into [^geom/__init__.py]:
[@techniques.html#creating_packages Creating Packages], we can code directly
into [^geom/__init__.py]:
from _geom import *
@@ -2022,8 +2042,8 @@ 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.
[endpage]
[beginpage Reducing Compiling Time]
[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
@@ -2079,15 +2099,15 @@ 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],
[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].]
a large source file, as explained in the [@../../../../v2/faq.html#c1204 FAQ].]
[endpage]
[endpage] [/ General Techniques]
[endsect]
[endsect] [/ General Techniques]

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -190,7 +190,7 @@ struct X
Y inner;
};
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(X_f_overloads, X::f, 1, 3)
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(f_member_overloads, f, 1, 3)
BOOST_PYTHON_MODULE(args_ext)
{
@@ -205,7 +205,7 @@ BOOST_PYTHON_MODULE(args_ext)
class_&lt;X&gt;(&quot;X&quot;, &quot;This is X's docstring&quot;)
.def(&quot;f1&quot;, &amp;X::f,
X_f_overloads(
f_member_overloads(
args(&quot;x&quot;, &quot;y&quot;, &quot;z&quot;), &quot;f's docstring&quot;
)[return_internal_reference&lt;&gt;()]
)

View File

@@ -13,7 +13,7 @@
p.c3 {font-style: italic}
h2.c2 {text-align: center}
h1.c1 {text-align: center}
</style>
</style>
</head>
<body>
@@ -96,158 +96,217 @@
<h2><a name="high_level">High Level Components</a></h2>
<dl>
<dt><a href="class.html">class.hpp/class_fwd.hpp</a></dt>
<dd>
<dl class="index">
<dt><a href="class.html#classes">Classes</a></dt>
<dd>
<dl>
<dt><a href="class.html">class.hpp/class_fwd.hpp</a></dt>
<dd>
<dl class="index">
<dt><a href="class.html#class_-spec">class_</a></dt>
<dt><a href="class.html#bases-spec">bases</a></dt>
<dt><a href="class.html#classes">Classes</a></dt>
<dd>
<dl class="index">
<dt><a href="class.html#class_-spec">class_</a></dt>
<dt><a href="class.html#bases-spec">bases</a></dt>
</dl>
</dd>
</dl>
</dd>
</dl>
</dd>
<dt><a href="def.html">def.hpp</a></dt>
<dd>
<dl class="index">
<dt><a href="def.html#functions">Functions</a></dt>
<dd>
<dl class="page-index">
<dt><a href="def.html#def-spec">def</a></dt>
<dt><a href="def.html">def.hpp</a></dt>
<dd>
<dl class="index">
<dt><a href="def.html#functions">Functions</a></dt>
<dd>
<dl class="page-index">
<dt><a href="def.html#def-spec">def</a></dt>
</dl>
</dd>
</dl>
</dd>
</dl>
</dd>
<dt><a href="def_visitor.html">def_visitor.hpp</a></dt>
<dd>
<dl class="index">
<dt><a href="def_visitor.html#classes">Classes</a></dt>
</dl>
</dd>
<dt><a href="enum.html">enum.hpp</a></dt>
<dd>
<dl class="index">
<dt><a href="enum.html#classes">Classes</a></dt>
<dd>
<dt><a href="def_visitor.html">def_visitor.hpp</a></dt>
<dd>
<dl class="index">
<dt><a href="enum.html#enum_-spec">enum_</a></dt>
<dt><a href="def_visitor.html#classes">Classes</a></dt>
</dl>
</dd>
</dl>
</dd>
<dt><a href="errors.html">errors.hpp</a></dt>
<dd>
<dl class="index">
<dt><a href="errors.html#classes">Classes</a></dt>
<dd>
<dt><a href="enum.html">enum.hpp</a></dt>
<dd>
<dl class="index">
<dt><a href=
<dt><a href="enum.html#classes">Classes</a></dt>
<dd>
<dl class="index">
<dt><a href="enum.html#enum_-spec">enum_</a></dt>
</dl>
</dd>
</dl>
</dd>
<dt><a href="errors.html">errors.hpp</a></dt>
<dd>
<dl class="index">
<dt><a href="errors.html#classes">Classes</a></dt>
<dd>
<dl class="index">
<dt><a href=
"errors.html#error_already_set-spec">error_already_set</a></dt>
</dl>
</dd>
<dt><a href="errors.html#functions">Functions</a></dt>
<dd>
<dl class="index">
<dt><a href=
</dl>
</dd>
<dt><a href="errors.html#functions">Functions</a></dt>
<dd>
<dl class="index">
<dt><a href=
"errors.html#handle_exception-spec">handle_exception</a></dt>
<dt><a href=
<dt><a href=
"errors.html#expect_non_null-spec">expect_non_null</a></dt>
<dt><a href=
<dt><a href=
"errors.html#throw_error_already_set-spec">throw_error_already_set</a></dt>
</dl>
</dd>
</dl>
</dd>
</dl>
</dd>
<dt><a href=
"exception_translator.html">exception_translator.hpp</a></dt>
<dd>
<dl class="index">
<dt><a href=
"exception_translator.html">exception_translator.hpp</a></dt>
<dd>
<dl class="index">
<dt><a href=
"exception_translator.html#functions">Functions</a></dt>
<dd>
<dl class="index">
<dt><a href=
<dd>
<dl class="index">
<dt><a href=
"exception_translator.html#register_exception_translator-spec">register_exception_translator</a></dt>
</dl>
</dd>
</dl>
</dd>
</dl>
</dd>
<dt><a href="init.html">init.hpp</a></dt>
<dd>
<dl class="index">
<dt><a href="init.html#classes">Classes</a></dt>
<dd>
<dt><a href="init.html">init.hpp</a></dt>
<dd>
<dl class="index">
<dt><a href="init.html#init-spec">init</a></dt>
<dt><a href="init.html#optional-spec">optional</a></dt>
<dt><a href="init.html#classes">Classes</a></dt>
<dd>
<dl class="index">
<dt><a href="init.html#init-spec">init</a></dt>
<dt><a href="init.html#optional-spec">optional</a></dt>
</dl>
</dd>
</dl>
</dd>
</dl>
</dd>
<dt><a href="iterator.html">iterator.hpp</a></dt>
<dd>
<dl class="index">
<dt><a href="iterator.html#classes">Classes</a></dt>
<dd>
<dt><a href="iterator.html">iterator.hpp</a></dt>
<dd>
<dl class="index">
<dt><a href="iterator.html#iterator-spec">iterator</a></dt>
<dt><a href="iterator.html#iterators-spec">iterators</a></dt>
<dt><a href="iterator.html#classes">Classes</a></dt>
<dd>
<dl class="index">
<dt><a href="iterator.html#iterator-spec">iterator</a></dt>
<dt><a href="iterator.html#iterators-spec">iterators</a></dt>
</dl>
</dd>
<dt><a href="iterator.html#functions">Functions</a></dt>
<dd>
<dl class="index">
<dt><a href="iterator.html#range-spec">range</a></dt>
</dl>
</dd>
</dl>
</dd>
<dt><a href="iterator.html#functions">Functions</a></dt>
<dd>
<dt><a href="module.html">module.hpp</a></dt>
<dd>
<dl class="index">
<dt><a href="iterator.html#range-spec">range</a></dt>
</dl>
</dd>
</dl>
</dd>
<dt><a href="module.html">module.hpp</a></dt>
<dd>
<dl class="index">
<dt><a href="module.html#macros">Macros</a></dt>
<dd>
<dl class="index">
<dt><a href=
<dt><a href="module.html#macros">Macros</a></dt>
<dd>
<dl class="index">
<dt><a href=
"module.html#BOOST_PYTHON_MODULE-spec">BOOST_PYTHON_MODULE</a></dt>
</dl>
</dd>
</dl>
</dd>
<dt><a href="operators.html">operators.hpp</a></dt>
<dd>
<dl class="index">
<dt><a href="operators.html#classes">Classes</a></dt>
<dd>
<dl class="index">
<dt><a href="operators.html#self_t-spec">self_t</a></dt>
<dt><a href="operators.html#other-spec">other</a></dt>
<dt><a href="operators.html#operator_-spec">operator_</a></dt>
</dl>
</dd>
<dt><a href="operators.html#objects">Objects</a></dt>
<dd>
<dl class="index">
<dt><a href="operators.html#self-spec">self</a></dt>
</dl>
</dd>
</dl>
</dd>
<dt><a href="scope.html">scope.hpp</a></dt>
<dd>
<dl class="index">
<dt><a href="scope.html#classes">Classes</a></dt>
<dd>
<dl class="index">
<dt><a href="scope.html#scope-spec">scope</a></dt>
</dl>
</dd>
</dl>
</dd>
<dt><a href="wrapper.html">wrapper.hpp</a></dt>
<dd>
<dl class="index">
<dt><a href="wrapper.html#classes">Classes</a></dt>
<dd>
<dl class="index">
<dt><a href="wrapper.html#override-spec">override</a></dt>
<dt><a href="wrapper.html#wrapper-spec">wrapper</a></dt>
</dl>
</dd>
</dl>
</dd>
</dl>
</dd>
<dt><a href="operators.html">operators.hpp</a></dt>
<dd>
<dl class="index">
<dt><a href="operators.html#classes">Classes</a></dt>
<dd>
<dl class="index">
<dt><a href="operators.html#self_t-spec">self_t</a></dt>
<dt><a href="operators.html#other-spec">other</a></dt>
<dt><a href="operators.html#operator_-spec">operator_</a></dt>
</dl>
</dd>
<dt><a href="operators.html#objects">Objects</a></dt>
<dd>
<dl class="index">
<dt><a href="operators.html#self-spec">self</a></dt>
</dl>
</dd>
</dl>
</dd>
<dt><a href="scope.html">scope.hpp</a></dt>
<dd>
<dl class="index">
<dt><a href="scope.html#classes">Classes</a></dt>
<dd>
<dl class="index">
<dt><a href="scope.html#scope-spec">scope</a></dt>
</dl>
</dd>
</dl>
</dd>
</dl>
<h2><a name="object_wrappers">Object Wrappers</a></h2>
@@ -357,6 +416,7 @@
</dd>
</dl>
</dd>
<dt><a href="slice.html">slice.hpp</a></dt>
<dd>
@@ -978,17 +1038,19 @@
<h2><a name="topics">Topics</a></h2>
<dl>
<dt><a href="callbacks.html">Calling Python Functions and Methods</a></dt>
<dt><a href="pickle.html">Pickle Support</a><br>
<a href="indexing.html">Indexing Support</a></dt>
</dl>
<dl>
<dt><a href="callbacks.html">Calling Python Functions and
Methods</a></dt>
<dt><a href="pickle.html">Pickle Support</a><br>
<a href="indexing.html">Indexing Support</a></dt>
</dl>
<hr>
<p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
19 July, 2003 <!--webbot bot="Timestamp" endspan i-checksum="39359" -->
31 October, 2004
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p>
<p class="c3">&copy; Copyright <a href=

236
doc/v2/wrapper.html Executable file
View File

@@ -0,0 +1,236 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<meta name="generator" content="HTML Tidy, see www.w3.org">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" type="text/css" href="../boost.css">
<title>Boost.Python - &lt;wrapper.hpp&gt;</title>
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
"header">
<tr>
<td valign="top" width="300">
<h3><a href="../../../../index.htm"><img height="86" width="277" alt=
"C++ Boost" src="../../../../boost.png" border="0"></a></h3>
<td valign="top">
<h1 align="center"><a href="../index.html">Boost.Python</a></h1>
<h2 align="center">Header &lt;wrapper.hpp&gt;</h2>
</table>
<hr>
<h2>Contents</h2>
<dl class="page-index">
<dt><a href="#introduction">Introduction</a></dt>
<dt><a href="#classes">Classes</a></dt>
<dd>
<dl class="page-index">
<dt><a href="#override-spec">Class template
<code>override</code></a></dt>
<dd>
<dl class="page-index">
<dt><a href="#override-spec-synopsis">Class
<code>override</code> synopsis</a></dt>
<dt><a href="#override-spec-observers">Class
<code>override</code> observer functions</a></dt>
</dl>
</dd>
<dt><a href="#wrapper-spec">Class template
<code>wrapper</code></a></dt>
<dd>
<dl class="page-index">
<dt><a href="#wrapper-spec-synopsis">Class <code>wrapper</code>
synopsis</a></dt>
<dt><a href="#wrapper-spec-observers">Class
<code>wrapper</code> observer functions</a></dt>
</dl>
</dd>
</dl>
</dd>
<dt><a href="#examples">Example(s)</a></dt>
</dl>
<hr>
<h2><a name="introduction"></a>Introduction</h2>
<p>To wrap a class <code>T</code> such that its virtual functions can be
"overridden in Python"&mdash;so that the corresponding method of a Python
derived class will be called when the virtual function is invoked from
C++&mdash;you must create a C++ wrapper class derived from ``T`` that
overrides those virtual functions so that they call into Python. This
header contains classes that can be used to make that job easier.</p>
<h2><a name="classes"></a>Classes</h2>
<h3><a name="override-spec"></a>Class <code>override</code></h3>
<p>Encapsulates a Python override of a C++ virtual function. An
<code>override</code> object either holds a callable Python object or
<code>None</code>.</p>
<h4><a name="override-spec-synopsis"></a>Class <code>override</code>
synopsis</h4>
<pre>
namespace boost
{
class override : object
{
public:
<i>unspecified</i> operator() const;
template &lt;class A0&gt;
<i>unspecified</i> operator(A0) const;
template &lt;class A0, class A1&gt;
<i>unspecified</i> operator(A0, A1) const;
...
template &lt;class A0, class A1, ...class A<i>n</i>&gt;
<i>unspecified</i> operator(A0, A1, ...A<i>n</i>) const;
};
};
</pre>
<h4><a name="override-spec-observers"></a>Class <code>override</code>
observer functions</h4>
<pre>
<i>unspecified</i> operator() const;
template &lt;class A0&gt;
<i>unspecified</i> operator(A0) const;
template &lt;class A0, class A1&gt;
<i>unspecified</i> operator(A0, A1) const;
...
template &lt;class A0, class A1, ...class A<i>n</i>&gt;
<i>unspecified</i> operator(A0, A1, ...A<i>n</i>) const;
</pre>
<dl class="function-semantics">
<dt><b>Effects:</b> If <code>*this</code> holds a callable Python
object, it is invoked with the specified arguments in the manner
specified <a href="callbacks.html">here</a>. Otherwise, throws <code><a
href="errors.html#error_already_set-spec">error_already_set</a></code>
.</dt>
<dt><b>Returns:</b> An object of unspecified type that holds the Python
result of the invocation and, when converted to a C++ type
<code>R</code>, attempts to convert that result object to
<code>R</code>. If that conversion fails, throws <code><a href=
"errors.html#error_already_set-spec">error_already_set</a></code>
.</dt>
</dl>
<h3><a name="wrapper-spec"></a>Class template <code>wrapper</code></h3>
<p>Deriving your wrapper class from both ``T`` <i>and</i>
``wrapper&lt;T&gt; makes writing that derived class easier.</p>
<h4><a name="wrapper-spec-synopsis"></a>Class template
<code>wrapper</code> synopsis</h4>
<pre>
namespace boost
{
class wrapper
{
protected:
override get_override(char const* name) const;
};
};
</pre>
<h4><a name="wrapper-spec-observers"></a>Class <code>wrapper</code>
observer functions</h4>
<pre>
override get_override(char const* name) const;
</pre>
<dl class="function-semantics">
<dt><b>Requires:</b> <code>name</code> is a <a href=
"definitions.html#ntbs">ntbs</a>.</dt>
<dt><b>Returns:</b> If <code>*this</code> is the C++ base class
subobject of a Python derived class instance that overrides the named
function, returns an <code>override</code> object that delegates to the
Python override. Otherwise, returns an <code>override</code> object
that holds <code>None</code>.</dt>
</dl>
<h2><a name="examples"></a>Example</h2>
<pre>
#include &lt;boost/python/module.hpp&gt;
#include &lt;boost/python/class.hpp&gt;
#include &lt;boost/python/wrapper.hpp&gt;
#include &lt;boost/python/call.hpp&gt;
using namespace boost::python;
// Class with one pure virtual function
struct P
{
virtual ~P(){}
virtual char const* f() = 0;
char const* g() { return "P::g()"; }
};
struct PCallback : P, wrapper&lt;P&gt;
{
char const* f()
{
#if BOOST_WORKAROUND(BOOST_MSVC, &lt;= 1300) // Workaround for vc6/vc7
return call&lt;char const*&gt;(this-&gt;get_override("f").ptr());
#else
return this-&gt;get_override("f")();
#endif
}
};
// Class with one non-pure virtual function
struct A
{
virtual ~A(){}
virtual char const* f() { return "A::f()"; }
};
struct ACallback : A, wrapper&lt;A&gt;
{
char const* f()
{
if (override f = this-&gt;get_override("f"))
#if BOOST_WORKAROUND(BOOST_MSVC, &lt;= 1300) // Workaround for vc6/vc7
return call&lt;char const*&gt;(f.ptr());
#else
return f();
#endif
return A::f();
}
char const* default_f() { return this-&gt;A::f(); }
};
BOOST_PYTHON_MODULE_INIT(polymorphism)
{
class_&lt;PCallback,boost::noncopyable&gt;("P")
.def("f", pure_virtual(&amp;P::f))
;
class_&lt;ACallback,boost::noncopyable&gt;("A")
.def("f", &amp;A::f, &amp;ACallback::default_f)
;
}
</pre>
<p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
31 October, 2004
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
<p><i>&copy; Copyright <a href="../../../../people/dave_abrahams.htm">Dave
Abrahams</a> 2004</i>

View File

@@ -47,7 +47,7 @@ object getitem(Target const& target, Key const& key)
template <class Key, class Value>
void setitem(object const& target, Key const& key, Value const& value)
{
return setitem(target, object(key), object(value));
setitem(target, object(key), object(value));
}
template <class Key>

View File

@@ -9,22 +9,22 @@
* compiler's bug.
*/
#include <boost/python.hpp>
#include <boost/type_traits/broken_compiler_spec.hpp>
using namespace boost::python;
bool accept_const_arg_noproto( const object)
BOOST_TT_BROKEN_COMPILER_SPEC( object )
#if BOOST_WORKAROUND(BOOST_MSVC, == 1200)
bool accept_const_arg( object );
#endif
bool accept_const_arg( const object )
{
return true;
}
bool accept_const_arg_with_proto( object);
bool accept_const_arg_with_proto( const object)
{
return true;
}
BOOST_PYTHON_MODULE( const_argument_ext)
BOOST_PYTHON_MODULE( const_argument_ext )
{
def( "accept_const_arg_noproto", accept_const_arg_noproto);
def( "accept_const_arg_with_proto", accept_const_arg_with_proto);
def( "accept_const_arg", accept_const_arg );
}

View File

@@ -3,9 +3,7 @@
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
"""
>>> from const_argument_ext import *
>>> accept_const_arg_noproto(1)
1
>>> accept_const_arg_with_proto(1)
>>> accept_const_arg(1)
1
"""