使用pybind11绑定数组

时间:2019-11-05 20:21:27

标签: pybind11

我在c中的结构如下

typedef struct _person{
         int id[10];
         int number[10];
}person;

如何使用pybind11绑定它?

1 个答案:

答案 0 :(得分:0)

当您希望数据可写时,似乎没有一种AFAICT的好方法(当数据为只读时,它的设计要少一些)。无论如何,假设您已经安装了numpy,以下操作可以解决问题:

#include <pybind11/pybind11.h>
#include <pybind11/pytypes.h>
#include <pybind11/numpy.h>


typedef struct _person{
    int id[10];
    int number[10];
} person;

PYBIND11_MODULE(person, m)
{   
    pybind11::class_<person>(m, "person", pybind11::buffer_protocol())
        .def(pybind11::init<>())
        .def_property("id", [](person &p) -> pybind11::array {
            auto dtype = pybind11::dtype(pybind11::format_descriptor<int>::format());
            auto base = pybind11::array(dtype, {10}, {sizeof(int)});
            return pybind11::array(
                dtype, {10}, {sizeof(int)}, p.id, base);
        }, [](person& p) {})
        .def_property("number", [](person &p) -> pybind11::array {
            auto dtype = pybind11::dtype(pybind11::format_descriptor<int>::format());
            auto base = pybind11::array(dtype, {10}, {sizeof(int)});
            return pybind11::array(dtype, {10}, {sizeof(int)}, p.number, base);
        }, [](person& p) {});
}

票证将提供空的基础对象,该对象将使数组表现为视图对象。没有基础,它将复制。您不需要属性设置器(如果实现,则可以设置数组,而不是数组项),并且可能会引发错误,而不是像我那样提供无操作。另外,如果确实有两个相同大小的数组,则可以使用辅助函数代替lambda。

绑定C内置数组的基本问题是python没有正确的数组类型(有一个基本的内存视图和模块数组,但是没有真正的数组类型),因此您需要从某个地方获取一个并pybind11宁愿选择numpy的游戏,因为它是镇上最好的游戏。

只是为了向您展示一种替代方法,在cppyy(http://cppyy.org)中,我采取了另一种方法:它具有低级数组视图,随后可以将其交给numpy进行查看或根据需要进行复制,因为它实现了完整的缓冲区协议。这样做的好处是可以由python用户决定最终用途。缺点是,如果您仍然要使用numpy,那将是一个额外的步骤。但它也可以在不安装numpy的情况下直接使用:

import cppyy

cppyy.cppdef("""
typedef struct _person{
    int id[10];
    int number[10];
} person;
""")

p = cppyy.gbl.person()
print(len(p.id), p.id)
print(list(p.id))

产生:

(10, <cppyy.LowLevelView object at 0x105ab33b0>)
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]