Привязка массива с помощью pybind11 - PullRequest
0 голосов
/ 05 ноября 2019

У меня есть структура в c следующим образом:

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

Как можно связать это, используя pybind11?

1 Ответ

0 голосов
/ 06 ноября 2019

Похоже, что вы не хотите использовать 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) {});
}

Билет должен предоставить пустой базовый объект, который заставит массив вести себя как объект представления. Без базы он делает копию. Вы не нуждаетесь в установщике свойств (который, в случае реализации, устанавливает массив, а не элементы массива) и может вызвать ошибку, вместо предоставления no-op, как я сделал. Кроме того, если у вас действительно есть два массива одинакового размера, вы можете использовать вспомогательную функцию вместо лямбда-выражений.

Основная проблема для связывания встроенных массивов 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]
...