...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
<boost/python/lvalue_from_pytype.hpp> supplies a facility for extracting C++ objects from within Python instances of a given type. This is typically useful for dealing with "traditional" Python extension types.
Class template lvalue_from_pytype will register from_python converters which, given an object of the given Python type, can extract references and pointers to a particular C++ type. Its template arguments are:
In the table below, x denotes an object of type PythonObject&
Parameter |
Requirements |
Semantics |
---|---|---|
Extractor |
a model of |
Extracts the lvalue from the Python object once its type has been confirmed |
python_type |
A compile-time constant |
The Python type of instances convertible by this converter. Python subtypes are also convertible. |
namespace boost { namespace python { template <class Extractor, PyTypeObject const* python_type> struct lvalue_from_pytype { lvalue_from_pytype(); }; }}
lvalue_from_pytype();
Registers converters which can convert Python objects of the given type to lvalues of the type returned by Extractor::execute.
extract_identity is a model of Extractor
which can be used in
the common case where the C++ type to be extracted is the same as the Python
object type.
namespace boost { namespace python { template <class InstanceType> struct extract_identity { static InstanceType& execute(InstanceType& c); }; }}
extract_member
is a model
of Extractor
which can be used in the common case in the common case where the C++ type
to be extracted is a member of the Python object.
namespace boost { namespace python { template <class InstanceType, class MemberType, MemberType (InstanceType::*member)> struct extract_member { static MemberType& execute(InstanceType& c); }; }}
static MemberType& execute(InstanceType& c);
c.*member
This example presumes that someone has implemented the standard noddy example module from the Python documentation, and we want to build a module which manipulates Noddys. Since noddy_NoddyObject is so simple that it carries no interesting information, the example is a bit contrived: it assumes you want to keep track of one particular object for some reason. This module would have to be dynamically linked to the module which defines noddy_NoddyType.
In C++:
#include <boost/python/module.hpp> #include <boost/python/handle.hpp> #include <boost/python/borrowed.hpp> #include <boost/python/lvalue_from_pytype.hpp> // definition lifted from the Python docs typedef struct { PyObject_HEAD } noddy_NoddyObject; using namespace boost::python; static handle<noddy_NoddyObject> cache; bool is_cached(noddy_NoddyObject* x) { return x == cache.get(); } void set_cache(noddy_NoddyObject* x) { cache = handle<noddy_NoddyObject>(borrowed(x)); } BOOST_PYTHON_MODULE(noddy_cache) { def("is_cached", is_cached); def("set_cache", set_cache); // register Noddy lvalue converter lvalue_from_pytype<extract_identity<noddy_NoddyObject>,&noddy_NoddyType>(); }
In Python:
>>> import noddy >>> n = noddy.new_noddy() >>> import noddy_cache >>> noddy_cache.is_cached(n) 0 >>> noddy_cache.set_cache(n) >>> noddy_cache.is_cached(n) 1 >>> noddy_cache.is_cached(noddy.new_noddy()) 0