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

As mentioned, one of the goals of Boost.Python is to provide a bidirectional
mapping between C++ and Python while maintaining the Python feel. Boost.Python
C++ objects are as close as possible to Python. This should
minimize the learning curve significantly.

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

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

voidf(strname){objectn2=name.attr("upper")();// NAME = name.upper()strNAME=name.upper();// betterobjectmsg="%s is bigger than %s"%make_tuple(NAME,name);}

In finer detail:

strNAME=name.upper();

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

objectmsg="%s is bigger than %s"%make_tuple(NAME,name);

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

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

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

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

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

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

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

enumchoice{red,blue};

the construct:

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

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

Note

what is a scope?

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

You can access those values in Python as

>>>my_module.choice.redmy_module.choice.red

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