有选择地将函数定义添加到python命名空间

时间:2019-03-08 18:07:34

标签: c++ python-2.7 boost-python

我想控制允许从python代码访问哪个函数。

在此结构中,我为Python定义了一些扩展功能:

if len(sys.argv) == 1:
    target_dir = '.'
else:
    target_dir = sys.argv[1]
target_dir = os.path.abspath(target_dir)

这是代码,我将定义添加到代码中,并将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;
};

我可以轻松地使用.def手动将函数扩展到Python中,但是我找不到任何解决方案来将其放入某种“ if”语句中,以检查是否允许将其添加到python中。当然,我可以将每个函数放在一个唯一的命名空间中,但这远非优雅,我认为这可能也会浪费一些内存。

对不起,我的英语不好,谢谢您提供的任何建议。

1 个答案:

答案 0 :(得分:1)

不必在一条语句中包含所有内容-链接调用的能力只是为了方便(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以公开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']

参考