Добавить определение функции выборочно в пространство имен Python - PullRequest
1 голос
/ 08 марта 2019

Я хочу контролировать, какой функции разрешено получать из кода Python.

Вот структура, где я определил некоторые функции для расширения Python:

struct Worldb
{
    void messagewindow(std::string msg) { functions.Messagewindow(msg); }
    void setnumber(int value) { publicnumber=value; }
    string getnumber() { return functions.converttostring(publicnumber); }
    int publicnumber;
};

А вот код, где я добавляю определение к коду и отправляю код Python компилятору:

Py_Initialize();

worldb.publicnumber = 1;

bp::object main_module = bp::import("__main__");
bp::object main_namespace = main_module.attr("__dict__");


main_namespace["Worldb"] = bp::class_<Worldb>("Worldb")
    .def("messagewindow", &Worldb::messagewindow)
    .def("setnumber", &Worldb::setnumber)
    .def("getnumber", &Worldb::getnumber);

main_namespace["cpp"] = bp::ptr(&worldb);//to prevent the worldb object copied 

bp::object compileit;
try
{
     compileit = exec(
         "cpp.messagewindow(cpp.getnumber())\n"
        "cpp.setnumber(8)\n",
        main_namespace);

}
catch(bp::error_already_set &)

Я могу легко расширить функции в Python с помощью .def, но я не могу найти никакого решения, чтобы поместить его в какое-то выражение «if», чтобы проверить, разрешено ли добавлять его в python или нет. Конечно, я могу поместить каждую функцию в уникальное пространство имен, но это далеко не элегантно, и я думаю, что, возможно, это тоже напрасная трата памяти.

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

1 Ответ

1 голос
/ 09 марта 2019

Нет необходимости иметь все в одном выражении - возможность цепочки вызовов является просто вопросом удобства (def и другие функции-члены возвращают ссылку на экземпляр, на котором они были вызваны, чтобы это произошло).

Если проанализировать оператор

main_namespace["Worldb"] = bp::class_<Worldb>("Worldb")
    .def("messagewindow", &Worldb::messagewindow)
    .def("setnumber", &Worldb::setnumber)
    .def("getnumber", &Worldb::getnumber);

, мы увидим, что он последовательно выполняет следующие функции:

  • Создает новый экземпляр class_<Worldb>
  • Вызывает функцию-член def для предоставления messagewindow
  • Вызывает функцию-член def для предоставления setnumber
  • Вызывает функцию-член def дляexpose getnumber
  • Назначает его main_namespace["Worldb"].

Мы можем переписать это, чтобы каждая часть была представлена ​​как отдельный оператор следующим образом:

{
    bp::class_<Worldb> test_binding = bp::class_<Worldb>("Worldb");
    test_binding.def("messagewindow", &Worldb::messagewindow);
    test_binding.def("setnumber", &Worldb::setnumber);
    test_binding.def("getnumber", &Worldb::getnumber);

    main_namespace["Worldb"] = test_binding;
}

Примечание. Мы вводим новую область видимости для ограничения времени жизни test_binding, которое больше не требуется после назначения.

Сделав это, тривиально представить отдельные методы условно.

Пример кода

#include <boost/python.hpp>

namespace bp = boost::python;

struct test
{
    void one() {}
    void two() {}
    void three() {}
};

int main()
{
    Py_Initialize();

    try {
        bp::object main_module = bp::import("__main__");
        bp::object main_namespace = main_module.attr("__dict__");

        // Simple bitmap of methods to expose:
        // * bit 0 -> one()
        // * bit 1 -> two()
        // * bit 2 -> three()
        uint32_t method_mask(5);

        {
            // Limit the scope of `test_binding` variable
            bp::class_<test> test_binding = bp::class_<test>("test");
            if ((method_mask & 1) == 1) {
                test_binding.def("one", &test::one);
            }
            if ((method_mask & 2) == 2) {
                test_binding.def("two", &test::two);
            }
            if ((method_mask & 4) == 4) {
                test_binding.def("three", &test::three);
            }

            main_namespace["test"] = test_binding;
        }

        exec("print dir(test)\n", main_namespace);
    } catch (bp::error_already_set &) {
        PyErr_Print();
    }

    Py_Finalize();

    return 0;
}

Консольный вывод

Примечание: Мы ожидаем, что one() и three() будут выставлены.Я переформатировал вывод для лучшей читаемости.

['__class__', '__delattr__', '__dict__', '__doc__', '__format__'
    , '__getattribute__', '__hash__', '__init__', '__instance_size__'
    , '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__'
    , '__sizeof__', '__str__', '__subclasshook__', '__weakref__'
    , 'one', 'three']

Ссылки

...