How to expose...
Contents
-
How to expose...
- static class data members
- static class functions
- module level objects
- mutable C++ object
- std::C++ container
- "Raw" function
- "Raw" constructor
- getter and setter methods as a property
- named constructors / factories (as Python initializers)
- boost.function objects
- a package within a single extension module
-
How to get...
- C++ object from Python
- SWIG exposed C++ object from Python
- Multithreading Support for my function
- ownership of C++ object
- ownership of C++ object extended in Python
- python object from derived C++ object
- python object from extended C++ object
- access to a Python extension in the same app that embeds Python?
- How to make...
- Howto debug your extensions..
static class data members
object x_class
= class_<X>("X")
.def( ... )
...
;
x_class.attr("fu") = X::fu;
x_class.attr("bar") = X::bar;
...Since version 1.30 you can use class_ method:
.add_static_property("name", &fget [,&fset])
static class functions
It's likely to be in 1.30 release.
Meanwhile you should do something which mirrors pure Python:
class foo(object):
def f(x,y):
return x*y
f = staticmethod(f)So in C++, it would be something like:
class_<foo>("foo")
.def("f", &foo::f)
.staticmethod("f") // **
;In version 1.33 staticmethod is already implemented, just use the same syntax as above.
Where the marked line would be implemented something like this:
self& staticmethod(char const* name)
{
dict d(handle<>(borrowed(downcast<PyTypeObject>(this->ptr())->tp_dict)));
object method = (object)(d[name]);
this->attr(name) = object(handle<>(
PyStaticMethod_New( callable_check(method.ptr()) )
));
return *this;
}To create overloaded staticmethods in python, you overload first, then you make it static.
If you want to expose a static function that returns a pointer to an already exposed C++ type, you have to specify a return policy. This is because python needs to know what to do with that pointer and how to track it after it is returned. The return policy specified what to do with the pointer, such as whether or not to free the memory after exiting. Like so:
class_<foo>("foo")
.def("f", &foo::f, return_value_policy<manage_new_object>())
.staticmethod("f") // **
;This has told python that a pointer returned from foo:f() must be managed as a new object and is to be deleted when out of scope or at exit. There are more return policies. Return policies are all subtypes of ResultConverterGenerator, check it out in the docs.
module level objects
at module creation time
First, create those objects like
object class_X = class_<X>("X");
object x = class_X();Second, expose them:
scope().attr("x") = x; // injects x into current scopeBy default current scope is module.
at run-time
Use a function:
template <class T>
void set(const std::string& name, const T& value) {
interpreter()->mainmodule()[name] = value;
}Note:: interpreter() is going to be added.
mutable C++ object
Perhaps you'd like the resulting Python object to contain a raw pointer to the argument? In that case, the caveat is that if the lifetime of the C++ object ends before that of the Python object, that pointer will dangle and using the Python object may cause a crash.
Here's how to expose mutable C++ object during module initialisation:
scope().attr("a") = object(ptr(&class_instance));
std::C++ container
You can always wrap the container with class_ directive. For example for std::map:
template<class Key, class Val>
struct map_item
{
typedef std::map<Key,Val> Map;
static Val& get(Map const& self, const Key idx) {
if( self.find(idx) != self.end() ) return self[idx];
PyErr_SetString(PyExc_KeyError,"Map key not found");
throw_error_already_set();
}
static void set(Map& self, const Key idx, const Val val) { self[idx]=val; }
static void del(Map& self, const Key n) { self.erase(n); }
static bool in(Map const& self, const Key n) { return self.find(n) != self.end(); }
static list keys(Map const& self)
{
list t;
for(Map::const_iterator it=self.begin(); it!=self.end(); ++it)
t.append(it->first);
return t;
}
static list values(Map const& self)
{
list t;
for(Map::const_iterator it=self.begin(); it!=self.end(); ++it)
t.append(it->second);
return t;
}
static list items(Map const& self)
{
list t;
for(Map::const_iterator it=self.begin(); it!=self.end(); ++it)
t.append( make_tuple(it->first, it->second) );
return t;
}
}
using namespace boost::python;
typedef std::map<Key,Val> Map;
class_<Map>("Map")
.def("__len__", &Map::size)
.def("__getitem__", &map_item<Key,Val>().get, return_value_policy<copy_non_const_reference>() )
.def("__setitem__", &map_item<Key,Val>().set)
.def("__delitem__", &map_item<Key,Val>().del)
.def("clear", &Map::clear)
.def("__contains__", &map_item<Key,Val>().in)
.def("has_key", &map_item<Key,Val>().in)
.def("keys", &map_item<Key,Val>().keys)
.def("values", &map_item<Key,Val>().values)
.def("items", &map_item<Key,Val>().items)
;To compile, you might need to add 'typename' before Map::const_iterator.
"Raw" function
I want to write in python:
def function( *args ):
# Mess arount with elements of args.
Method 1 (old way)
You can make one with the library's implementation details. Be warned that these interfaces may change, but hopefully we'll have an "official" interface for what you want to do by then.
python::objects::function_object(
f // must be py_function compatible
, 0, std::numeric_limits<unsigned>::max() // arity range
, python::detail::keyword_range()); // no keywordswill create a Python callable object.
f is any function pointer, function reference, or function object which can be invoked with two PyObject* arguments and returns something convertible to a PyObject*.
You can add this to your module namespace with:
scope().attr("name") = function_object(f, ... );Now you can also
class_<foo>("foo")
.def("bar",function_object(f, ... ) );as well, but not
function_object bar(f, ... );
...
class_<foo>("foo")
.def("bar",bar);because function_object is a function, not a class.
Method 2 (new way)
There's a poorly documented function called raw_function in boost::python that makes defining the functions with arbitrary arguments much easier. Another advantage of this method is that this is not using any functionality from the details namespace, so this should be more stable.
This is our goal:
To accomplish this from C++, we must wrap our functionality into a function with the following signature:
Then we can use raw_function to add it to our class:
raw_function takes two parameters - the function pointer and the minimum number of arguments.
"Raw" constructor
What if you wanted to make a constructor that takes in an arbitrary number of arguments and/or an arbitrary number keyword arguments?
It turns out that boost::python can do raw_function, and it can do make_constructor, but how to combine these two to get a raw constructor is not obvious. We describe two methods. Method 1 uses only the public API, which makes it reliable, but the code is a bit hack-ish. Method 2 leads to straight-forward client code, but requires one to write a custom header that uses internal implementation details of boost::python to get the desired effect.
Method 1 (official)
This is how the boost::python unit tests implement a raw constructor, see test/raw_ctor.cpp. A documented example:
