2015-07-17 25 views
5

Próbuję zbudować moduł Pythona w C++, który przekształca wektor 2D na tablicę Numpy 2D. Co tutaj jest niepoprawne - prawdopodobnie potrzeba transformacji do obiektu python boost z PyObject *?Python * do zwiększenia :: python :: obiekt

boost::python::object build_day(int year, int day) { 

    PyObject* arr; 
    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}; 
    arr = PyArray_SimpleNewFromData(2, dims, NPY_FLOAT, &array); 

    return arr; 
} 

BOOST_PYTHON_MODULE(sumpar) { 
    using namespace boost::python; 
    def("build_day", build_day, args("year", "day")); 
} 

Odpowiedz

4

boost::python::object stanowi ogólny interfejs do obiektów Pythona. Aby skonstruować jeden z PyObject*, należy najpierw zbudować boost::python::handle<>, który jest w zasadzie inteligentnym wskaźnikiem zaprojektowanym do zarządzania obiektami Pythona zliczanymi z odwołaniem (PyObject* lub typami pochodnymi). Często używa się handle<> między granicą między kodem wyższego poziomu Boost.Python i Python/C API.

namespace python = boost::python; 
PyObject* py_object = get_py_object(); 
python::handle<> handle(py_object); 
boost::python object(handle); 

Zauważ, że handle podzieli własność PyObject*, a podczas zniszczenia, będzie to zmniejszyć liczbę odwołań na PyObject ta zarządza. Dlatego w trakcie budowy ważne jest, aby określić, czy handle<> potrzebuje zwiększyć liczbę referencyjną o PyObject*.

Jeśli PyObject miał już jej Ilość referencyjna wzrosła, a następnie użyć:

namespace python = boost::python; 
PyObject* py_object = ...; 
python::handle<> handle(py_object); 
python::object object(handle); 

Jeśli PyObject nie miał jej Ilość referencyjna wzrosła, a uchwyt musi to zrobić, a następnie użyj funkcji borrowed() podczas budowy:

namespace python = boost::python; 
PyObject* py_object = ...; 
python::handle<> handle(python::borrowed(py_object)); 
python::object object(handle); 

Powyżej znajduje się pełna przykład demonstrating konstruowania boost::python::object od A PyObject*:

#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")); 
} 

Interactive Wykorzystanie:

>>> import example 
>>> day = example.build_day(1, 2); 
>>> assert(day) 

Należy pamiętać, że aby stworzyć minimalną kompletny przykład, powyższy przykład ma szydzili PyArray_SimpleNewFromData() że po prostu zwraca ciąg Pythona. Ważne jest, aby zapoznać się z dokumentacją w celu ustalenia, czy PyObject* została wypożyczona, czy też nie, oraz czy istnieją jakieś wymagania dotyczące czasu życia między obiektem a jego argumentami. W przypadku PyArray_SimpleNewFromData(), zwrócony PyObject*:

  • już ilość jego odniesienia zwiększona
  • Żywotność pamięci podstawowego dostarczanego do tablicy musi być co najmniej tak długa jak zwróconej PyObject. Funkcja build_day() w pierwotnym pytaniu nie spełnia tego wymogu.
0

Moja sugestia jest użycie zmiennych i obiektów udostępnianych przez boost :: python, więc jeśli chcesz zwrócić tablicę do pytona powinno być, że będzie to dobry pomysł, aby użyć boost :: python :: DICT, coś jak ...

boost::python::dict arr; 

int i = 0; 
for (auto &item: array) { 
    arr[i] = item; 
    ++i; 
} 

return arr;