Boost-python чистый виртуальный обнаружение отсутствующей реализации

У меня есть класс С++ с чистым виртуальным методом, открытым для python с использованием boost-python. Я вызываю виртуальную функцию из C++ и предполагаю, что виртуальная функция реализована в python. Все работает, если функция реализована, но если нет, я получаю неприятное исключение.

Я пытаюсь найти способ определить, действительно ли метод реализован без вызова при загрузке класса.

Примерно так выглядит код

#include <boost/python.hpp>

using namespace boost::python;

public Foo {
public:
   void func() = 0;
}

class PyFoo : public Foo, public boost::python::wrapper<Foo> {
public:
    void func() override {
        get_override("func")();
    }
};

BOOST_PYTHON_MODULE(example)
{
    using namespace boost::python;
    class_<PyFoo>, boost::noncopyable>("Foo")
        .def("func", pure_virtual(&PyFoo::func))
        ;
}

void create {
    object main_module = import("__main__");
    object main_namespace = main_module.attr("__dict__");

    std::string overrideCommand(
    R"(
    import example

    class MyFoo(example.Foo):
        def __init__(self):
            example.Foo.__init__(self)

    # virtual function in C++. (Should be defined)
    #    def func(self):
    #        print('func called')
    )");

    boost::python::exec(overrideCommand.c_str(), main_namespace);
    result = eval("MyFoo()", main_namespace);

    // Can I detect if 'result' has func implemented? If I call it and it
    // is not defined death results. I have tried:
    object attr = result.attr("func");

    // but attr always seems to be set even if there is no function,
    // I think from the base class Foo.

    // This is the call:
    Foo& t = extract<Foo&>(result);
    t.func();
}

person John Neave    schedule 07.02.2019    source источник


Ответы (2)


Вы можете использовать PyCallable_Check.

if (!PyCallable_Check(result.func()))
{
    PyErr_SetString(PyExc_TypeError, error_msg.str().c_str());
    python::throw_error_already_set();
}
person bogdan tudose    schedule 07.02.2019
comment
Я не мог заставить это скомпилировать точно, поэтому я пробовал различные версии этого, но он всегда говорил, что его можно вызывать, даже если вызов разбился. Я думаю, что базовый класс определяет заглушку, которую он считает вызываемой 'PyObject *callback = PyObject_GetAttrString(result.ptr(), func); если (!PyCallable_Check(обратный вызов))' - person John Neave; 08.02.2019

Я нашел решение. Работающий не элегантный. Я добавил метод:

bool isThere()  {
    auto obj = get_override("func");
    return PyCallable_Check(obj.ptr());
}

в ФуПи. Затем:

FooPy& t = extract<FooPy&>(result);
t.isThere();
person John Neave    schedule 08.02.2019