Используя boost :: python, как вернуть вектор структур в виде списка dicts для Python? - PullRequest
0 голосов
/ 30 января 2019

У меня есть следующий код C ++:

    struct MyType { int x, y; };
    struct A { 
        std::vector<MyType> get_data();
    };

, который я хочу связать с Python с помощью Boost Python, чтобы его можно было использовать следующим образом:

    a = A()
    ret = a.get_data();
    for r in ret:
        print('x=%d; y=%d;' % (r['x'], r['y']))

ЧтоУ меня сейчас довольно наивный:

    BOOST_PYTHON_MODULE(pyA) { 
        class_<A>("A").def("get_data", &A::get_data);
    }

, который дает мне, как и ожидалось, следующую ошибку

     TypeError: No to_python (by-value) converter found for C++ type

, когда я пытаюсь вызвать функцию get_data() из кода Python,

Я видел здесь сообщения (такие как std :: vector to boost :: python :: list ), которые описывают, как использовать vector_indexing_suite для преобразования std::vector<T> вlist для некоторых типов T (например, числа с плавающей запятой, строки), но я не уверен, как расширить это, чтобы справиться и с моим преобразованием struct -> dict.Любая помощь будет принята с благодарностью.

Ответы [ 2 ]

0 голосов
/ 18 февраля 2019

В итоге я принял решение, подобное следующему, которое я публикую здесь на случай, если оно пригодится кому-то еще в будущем.Это можно улучшить, добавив в буст квалификатор «только для чтения», но я этого еще не сделал.

#include <boost/python.hpp>
using namespace boost::python;

struct Point { 
    int x, y;
};

using Points = std::vector<Point>;

struct Converter
{
    static PyObject* convert(const Points& v)
    {
        boost::python::list ret;
        for (const auto& c : v) {
            boost::python::dict *r = new boost::python::dict();
            (*r)["x"] = c.x;
            (*r)["y"] = c.y;
            ret.append(boost::python::object(*r));
         }
        return boost::python::incref(ret.ptr());
    }
};

BOOST_PYTHON_MODULE(mymodule)
{
    boost::python::to_python_converter<Points, Converter>();

    class_<MyClass, boost::noncopyable>("MyClass")
        .def("get_data", &MyClass::get_data);
}
0 голосов
/ 31 января 2019

Ниже, как выставить ваш код C++ на Python.MyType нуждается в перегруженном операторе сравнения "равно", а сам MyType должен быть выставлен на Python.

#include <boost/python.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
using namespace boost::python;

struct MyType { 
    int x, y;  
    bool operator==(const MyType& data) const {
        return this->x == data.x && this->y == data.y;
    }   
};
struct A { 
    std::vector<MyType> get_data() const { return {{1,2},{3,4}};};
};

BOOST_PYTHON_MODULE(pyA) {
    class_<MyType>("MyType")
        .def_readwrite("x", &MyType::x)
        .def_readwrite("y", &MyType::y);
    class_<std::vector<MyType>>("MyList")
        .def(vector_indexing_suite<std::vector<MyType>>());
    class_<A>("A").def("get_data", &A::get_data);
}

Ниже слегка измененный скрипт Python.get_data() Возвращаемый тип списка, поэтому к нему нужно обращаться как таковому.Если вы хотите, чтобы это был диктат, то конвертируйте его в диктовку в Python.

import pyA 

a = pyA.A()
ret = a.get_data();
for r in ret:
    print('x=%d; y=%d;' % (r.x, r.y))
...