I am wrapping C++ classes with boost-python and I am wondering is there is a better way to do it than what I am doing now.
The problem is that the classes have getters/setters that have the same name and there doesn't seem to be a painless way to wrap this with boost-python.
Here is a simplified version of the problem. Given this class:
#include <boost/python.hpp>
using namespace boost::python;
class Foo {
public:
double
x() const
{
return _x;
}
void
x(const double new_x)
{
_x = new_x;
}
private:
double _x;
};
I would like to do something like:
BOOST_PYTHON_MODULE(foo)
{
class_<Foo>("Foo", init<>())
.add_property("x", &Foo::x, &Foo::x)
;
}
This doesn't work because boost-python can't figure out which version of the function to use.
In fact, you can't even do
.def("x", &Foo::x)
for the same reason.
I was re-reading the tutorial at boost.org and the section on overloading seemed super promising. Unfortunately it doesn't seem to be what I'm looking for.
In the overloading section, it mentions a BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS
macro that works like this:
if there were another member function in Foo
that took defaulted arguments:
void z(int i=42)
{
std::cout << i << "\n";
}
you can then use the macro:
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(z_member_overloads, z, 0, 1)
and then in the BOOST_PYTHON_MODULE
:
.def("z", &Foo::z, z_member_overloads())
z_member_overloads
lets you call def
once and it will expose methods to python for both 0 arguments and 1 argument.
I was hoping that this would work for my x()
and x(double val)
getter/setter, but it doesn't work.
doing:
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(x_member_overloads, x, 0, 1)
...
.def("x", &Foo::x, x_member_overloads())
doesn't compile:
error: no matching member function for call to 'def'
.def("x", &Foo::x, x_member_overloads())
~^~~
Question: So, is there another macro or something that can make this work?
For completeness, this is how I'm currently handling cases like this:
.add_property(
"x",
make_function(
[](Foo& foo) {
return foo.x();
},
default_call_policies(),
boost::mpl::vector<double, Foo&>()
),
make_function(
[](Foo& foo, const double val) {
foo.x(val);
},
default_call_policies(),
boost::mpl::vector<void, Foo&, double>()
)
)
“Another thing to keep in mind when using getter (and setter) methods is that properties cannot share the same name as the getter/setter function.”
Getters and Setters in python are often used when: We use getters & setters to add validation logic around getting and setting a value. To avoid direct access of a class field i.e. private variables cannot be accessed directly or modified by external user.
@property is used to get the value of a private attribute without using any getter methods. We have to put a line @property in front of the method where we return the private variable. To set the value of the private variable, we use @method_name.
You can use the magic methods __getattribute__ and __setattr__ . Be aware that __getattr__ and __getattribute__ are not the same. __getattr__ is only invoked when the attribute is not found.
You can do this by casting to appropriate overload (untested):
class_<Foo>("Foo", init<>())
.add_property("x",
static_cast< double(Foo::*)() const >(&Foo::x), // getter
static_cast< void(Foo::*)(const double) >(&Foo::x)) // setter
;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With