boost::python::object 为 Python 对象提供了一个通用接口。要从PyObject* 构造一个,首先必须构造一个boost::python::handle<>,它本质上是一个智能指针,旨在管理引用计数的Python 对象(PyObject* 或派生类型)。人们经常在 Boost.Python 的高级代码和 Python/C API 之间的边界之间使用handle<>。
namespace python = boost::python;
PyObject* py_object = get_py_object();
python::handle<> handle(py_object);
boost::python object(handle);
请注意,handle 将共享 PyObject* 的所有权,并且在销毁期间,它将减少它正在管理的 PyObject 上的引用计数。因此,在构造过程中,重要的是要指定handle<>是否需要增加PyObject*的引用计数。
如果PyObject 的引用计数已经增加,则使用:
namespace python = boost::python;
PyObject* py_object = ...;
python::handle<> handle(py_object);
python::object object(handle);
如果PyObject的引用计数没有增加,句柄必须这样做,那么在构造过程中使用borrowed()函数:
namespace python = boost::python;
PyObject* py_object = ...;
python::handle<> handle(python::borrowed(py_object));
python::object object(handle);
这是一个完整的例子 demonstrating 从 PyObject* 构造一个 boost::python::object:
#include <vector>
#include <boost/python.hpp>
// Mocks...
enum { NPY_FLOAT };
typedef int npy_intp;
PyObject* PyArray_SimpleNewFromData(int, npy_intp*, int, void*)
{
return PyString_FromString("hello world");
}
boost::python::object build_day(int year, int day)
{
const int HEIGHT = 5;
const int WIDTH = 5;
std::vector<std::vector<float> > array(
WIDTH, std::vector<float>(HEIGHT));
npy_intp dims[2] = {WIDTH, HEIGHT};
namespace python = boost::python;
PyObject* arr = PyArray_SimpleNewFromData(2, dims, NPY_FLOAT, &array);
python::handle<> handle(arr);
return python::object(handle);
}
BOOST_PYTHON_MODULE(example)
{
namespace python = boost::python;
python::def("build_day", &build_day, python::args("year", "day"));
}
互动使用:
>>> import example
>>> day = example.build_day(1, 2);
>>> assert(day)
请注意,要创建一个最小的完整示例,上面的示例有一个模拟的PyArray_SimpleNewFromData(),它只返回 Python 字符串。请务必查阅文档以确定 PyObject* 是否被借用,以及对象及其参数之间是否存在任何生命周期要求。对于PyArray_SimpleNewFromData(),返回的PyObject*:
- 其引用计数已经增加
- 提供给数组的底层内存的生命周期必须至少与返回的
PyObject 一样长。原题中的build_day()函数不满足这个要求。