2015-07-17 19 views
5

C++'da bir 2B vektörünü bir Numpy 2D dizisine dönüştüren bir Python modülü oluşturmaya çalışıyorum. Burada yanlış olan - muhtemelen PyObject * 'den bir destek python nesnesine ihtiyaç duyulan bazı dönüşümler var mı?Python * artırmak için :: python :: object

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

cevap

4

boost::python::object Python nesnelerine genel bir arayüz sağlar. Bir PyObject*'dan birini oluşturmak için, önce bir referans noktası sayılan Python nesnelerini (PyObject* veya türetilmiş türler) yönetmek için tasarlanmış bir akıllı işaretçi olan bir boost::python::handle<> oluşturmak gerekir. Biri, Boost.Python'un üst düzey kodu ile Python/C API'si arasındaki sınır arasında handle<> kullanır. handlePyObject* sahipliğini paylaşacak ve yıkım sırasında, o yönetmek olduğu PyObject başvuru sayısı azalacak

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

Not. Bu nedenle, inşaat sırasında, handle<>'un PyObject* referans sayısının artırılması gerekip gerekmediğini belirtmek önemlidir. Zaten başvuru sayısı artmıştı etti PyObject ise

sonra kullanın: başvuru sayısı arttı olmamıştır ve sap yapmalısın

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

PyObject, o zaman inşaat sırasında borrowed() işlevini kullanın:

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

birinşa tam bir örnek demonstrating olduğunuPyObject* bir den:

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

Etkileşimli kullanımı:

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

Not minimal eksiksiz bir örnek oluşturmak için, yukarıdaki örnek sadece Python dize döndürür bir alay PyArray_SimpleNewFromData() sahiptir. PyObject*'un ödünç alınıp alınmadığını ve nesne ile argümanları arasında herhangi bir ömür boyu gereksinim olup olmadığını belirlemek için belgelere başvurmak önemlidir. PyArray_SimpleNewFromData() durumunda, PyObject* bulundu:

  • önce başvuru sayısı en azından uzun geri PyObject gibi olmalıdır
  • diziye mesafede yatan bellek süresi artmış bulunmaktadır. Özgün sorudaki build_day() işlevi bu gereksinimi karşılayamıyor.
0

Önerim bunu bir destek kullanmak iyi bir fikir olacağını olabilir olmalıdır piton için bir dizi dönmek istiyorum eğer öyleyse, boost :: piton tarafından sağlanan değişkenleri ve nesneleri kullanmaktır :: piton :: dict, gibi bir şey ...

boost::python::dict arr; 

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

return arr;