有选择地将函数定义添加到 python 命名空间
Add function definition selectively to a python namespace
我想控制允许从 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 &)
我可以轻松地使用 .def 手动将函数扩展到 Python,但我找不到任何解决方案将其放入某种 "if" 语句中,以检查它是否被允许添加到 python 与否。当然,我可以将每个函数放入一个唯一的命名空间,但这远非优雅,我认为这也可能浪费一些内存。
抱歉我的英语不好,谢谢你给的任何建议。
没有必要在一个语句中包含所有内容——链接调用的能力只是为了方便(def
和其他成员函数 return 引用它们所在的实例调用让这发生)。
如果我们分析语句
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']
参考资料
我想控制允许从 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 &)
我可以轻松地使用 .def 手动将函数扩展到 Python,但我找不到任何解决方案将其放入某种 "if" 语句中,以检查它是否被允许添加到 python 与否。当然,我可以将每个函数放入一个唯一的命名空间,但这远非优雅,我认为这也可能浪费一些内存。
抱歉我的英语不好,谢谢你给的任何建议。
没有必要在一个语句中包含所有内容——链接调用的能力只是为了方便(def
和其他成员函数 return 引用它们所在的实例调用让这发生)。
如果我们分析语句
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']