如何在boost::python中为模块添加属性?
你可以通过 getter 和 setter 来给一个类添加属性(这是个简单的例子):
class<X>("X")
.add_property("foo", &X::get_foo, &X::set_foo);
这样你就可以在 Python 中像这样使用它:
>>> x = mymodule.X()
>>> x.foo = 'aaa'
>>> x.foo
'aaa'
但是,如何给一个模块本身(而不是类)添加属性呢?
有
scope().attr("globalAttr") = ??? something ???
还有
def("globalAttr", ??? something ???);
我可以通过上面两种方法添加全局函数和我的类的对象,但似乎无法像在类中那样添加属性。
2 个回答
3
boost.python/HowTo 在 Python Wiki 上有一个例子,展示了如何在 BOOST_PYTHON_MODULE
中将 C++ 对象作为模块属性暴露出来:
namespace bp = boost::python;
BOOST_PYTHON_MODULE(example)
{
bp::scope().attr("my_attr") = bp::object(bp::ptr(&my_cpp_object));
}
如果想在 BOOST_PYTHON_MODULE
外部设置这个属性,可以使用
bp::import("example").attr("my_attr") = bp::object(bp::ptr(&my_cpp_object));
现在你可以在 Python 中做类似这样的事情
from example import my_attr
当然,你需要提前注册 my_cpp_object
的类(比如,你可以在同一个 BOOST_PYTHON_MODULE
调用中完成这件事),并确保 C++ 对象的生命周期比 Python 模块的生命周期长。你可以使用任何 bp::object
,而不一定要包装 C++ 对象。
需要注意的是,BOOST_PYTHON_MODULE
会吞掉异常,也就是说如果你出错了,系统不会给你任何错误提示,BOOST_PYTHON_MODULE
生成的函数会直接返回。为了方便调试这种情况,你可以在 BOOST_PYTHON_MODULE
内部捕获异常,或者临时在 BOOST_PYTHON_MODULE
的最后一行添加一些日志语句,以便查看是否到达了这一行:
BOOST_PYTHON_MODULE(example)
{
bp::scope().attr("my_attr2") = new int(1); // this will compile
std::cout << "init finished\n"; // OOPS, this line will not be reached
}
3
__getattr__
和 __setattr__
这两个东西在模块中是不会被调用的,所以你在普通的Python里不能这样做,除非使用一些小技巧,比如把一个类存储在模块的字典里。考虑到这一点,在Boost Python中也很可能没有什么优雅的方法可以做到这一点。