1

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?

0

1 Answer 1

3

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.