Context: I've recently been using pybind11 to put a python frontend on an old c++ project of mine. This has mostly been a breeze (thanks pybind11 devs!), but there are some areas where I've had to resort to some really ugly hacks that I'd rather like to avoid.
Question: When translating from py::object (user input in python) to a class in my code that acts a lot like py::object (call it myobject), I need to detect the type of py::object. This is trivial for int, float, string, list etc, but I can't see an obvious way for complex numbers and function handles. Here's my current workaround for complex numbers:
bool isComplex(py::object src)
{
// put src into a buffer accessible from both C++ and python (i is an index in this buffer)
int i = pyosetsrc(src);
// Build a python function to do the "is it complex" test
std::string fn;
fn = "isinstance(mycode.pyogetsrc("; // pyogetsrc(i) gets src back out of the shared buffer
fn += std::to_string(i);
fn += "), complex)";
// Wrap this in an eval statement
std::string evalfn;
evalfn = "eval('";
evalfn += fn;
evalfn += "')";
// Run the eval statement
py::object builtins = py::module_::import("builtins");
py::object eval = builtins.attr("eval");
py::object res = eval(evalfn);
// Process the result
return py::isinstance<py::bool_>(res) && py::cast<py::bool_>(res);
}
and for function handles there's a similar hack, this time with:
fn = "callable(mycode.pyogetsrc(";
fn += std::to_string(i);
fn += "))";
is there a less awful alternative I'm missing here?
all of isinstance and callable and complex are in the builtin module, you just need to get them and call them.
bool is_complex(py::object src)
{
py::object builtins = py::module_::import("builtins");
py::object isinstance_function = builtins.attr("isinstance");
py::object complex_class = builtins.attr("complex");
// to test if an object is callable
py::object callable_function = builtins.attr("callable");
// if not bool let exception be thrown
return py::cast<py::bool_>(isinstance_function(src, complex_class));
}
import pybind_example
a = 5+4j
print(pybind_example.is_complex(a)) # prints True
you could store those objects somewhere to avoid importing them every time .... unless you are planning on using multiple interpreters or restarting the interpreter.