如何在boost::python中为模块添加属性?

12 投票
2 回答
5293 浏览
提问于 2025-04-15 22:08

你可以通过 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中也很可能没有什么优雅的方法可以做到这一点。

撰写回答