簡體   English   中英

使用C ++和Python訪問數組

[英]Access an Array with both C++ and Python

我正在模擬一個由約100,000個恆星組成的迷你星系。 我想在Python中進行視覺表示,在C ++中進行大量計算。 使用ctypes,我可以從Python調用C ++函數。

我基本上想要的是RAM中存在的數組,可以由python和C ++訪問。 然后,在python中調用函數update()時,C ++將更新數組。 重要的是,C ++實際上僅更改數組中的值。 一直進行復制將非常耗時。

我是一個初學者,尤其是在C ++中,所以我真的不知道在哪里可以找到正確的信息以及要使用的關鍵字。 當然歡迎提出有關如何做的想法,但是一些信息鏈接也將不勝感激。

最好,

您可以使用python C / C ++ API構建C ++ python包裝器模塊:

https://docs.python.org/2/extending/extending.html

我將使用提供服務的python API創建一個C ++模塊( dataUpdater ),讓我們對其進行調用, update ,該操作應該會接收要將數據加載到其中的Python對象。

在您的Python端,每當我想從C ++加載數據時,我都會調用dataUpdater.update

編輯:

另一種選擇是使您的C ++模塊的行為類似於提供數據訪問服務的數據結構,例如:

  • getValueAt(index)
  • setValueAt(index)
  • getSize()

並在python端使用它:

for i in xrange(dataUpdater.getSize()):
    val = dataUpdater.getValueAt(i)
    ...

您應該完全檢查有關此問題的Python文檔:

https://docs.python.org/2/extending/

考慮到文檔,您可以定義一個新的Type; 假設星星將是雙精度數組:

typedef struct {
    PyObject_HEAD
    double * Stars;
} Galaxy;

然后定義數學運算方法...(python doc)

static PyObject* Galaxy_calc(Galaxy *self, PyObject *args)
{
     double * Star_temp;   

     /* Your Array is referenced by self->Stars*/
     Star_temp = self->Stars;

     /* Do the math in C++ */
     // All necessary calculations go here.
};

將這些方法包含在新定義的類型(Galaxy)中相當容易,您只需設置變量即可:

static PyMethodDef Galaxy_methods[] = 
{
    {"calc", (PyCFunction)Galaxy_calc, METH_VARARGS,"Performs stelar calculations."},
    {NULL}  /* Sentinel */
};


static PyMemberDef Galaxy_members[] = 
{    {"Stars", T_OBJECT_EX, offsetof(Galaxy, Galaxy), 0, "Galaxy Stars"},
    {NULL}  /* Sentinel */
};

現在只需將Galaxy_methods var包含在下面的適當位置

static PyTypeObject Galaxy_GalaxyType = {
    PyObject_HEAD_INIT(NULL)
    0,                         /*ob_size*/
    "Galaxy.Galaxy ",           /*tp_name*/
    sizeof(Galaxy),            /*tp_basicsize*/
    0,                         /*tp_itemsize*/
    (destructor)Galaxy_dealloc, /*tp_dealloc*/
    0,                         /*tp_print*/
    0,                         /*tp_getattr*/
    0,                         /*tp_setattr*/
    0,                         /*tp_compare*/
    0,                         /*tp_repr*/
    0,                         /*tp_as_number*/
    0,                         /*tp_as_sequence*/
    0,                         /*tp_as_mapping*/
    0,                         /*tp_hash */
    0,                         /*tp_call*/
    0,                         /*tp_str*/
    0,                         /*tp_getattro*/
    0,                         /*tp_setattro*/
    0,                         /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,          /*tp_flags*/
    "Galaxy objects",          /* tp_doc */
    0,                         /* tp_traverse */
    0,                         /* tp_clear */
    0,                         /* tp_richcompare */
    0,                         /* tp_weaklistoffset */
    0,                         /* tp_iter */
    0,                         /* tp_iternext */
    Galaxy_methods,            /* tp_methods */
    Galaxy_members,            /* tp_members */
    0,                         /* tp_getset */
    0,                         /* tp_base */
    0,                         /* tp_dict */
    0,                         /* tp_descr_get */
    0,                         /* tp_descr_set */
    0,                         /* tp_dictoffset */
   (initproc)Galaxy_init,      /* tp_init */
    0,                         /* tp_alloc */
    Galaxy_new,                /* tp_new */
};

使用上面提到的python文檔來實現新的,alloc,dealloc和init方法(這些非常簡單),就可以了!

正確執行此操作實際上非常復雜。 首先,您應該在python中使用numpy包作為數組。 然后,您將定義一個C接口,如https://docs.python.org/2/c-api/中所述 (這是參考手冊,因此您可能要先閱讀並嘗試使用https://docs.python.org/2/extending/index.html 。)最重要的是,您將需要使用緩沖區接口( https ://docs.python.org/2/c-api/buffer.html#bufferobjects )訪問numpy數組。

ctypes似乎也對連續數組有一些支持,但是我沒有經驗。 但是,如果您在Python端對數組進行任何處理,則需要使用numpy ,我認為ctypes不支持。

這是關於如何使用Boost.Python完成此任務的另一個建議。

讓我們將代碼組織成3個文件: setup.py (負責編譯擴展代碼),僅使用擴展代碼的Python腳本以及擴展代碼本身:

.
├── galaxy.cpp
├── main.py
└── setup.py

galaxy.cpp :請注意, galaxy.cpp異常,因此,可以通過分配給尚未初始化的Star和其他C ++ galaxy.cpp來產生分段錯誤。 如果您修改此代碼,請務必始終將BOOST_PYTHON_MODULE命名為文件本身。

#include <vector>

#include <boost/python.hpp>

class Star {
public:
    Star(double mass): mass(mass) {}

    bool set_mass(double given_mass) {
        this->mass = given_mass;
        return true;
    }
private:
    double mass;
};

class Galaxy {
public:
    Galaxy(const boost::python::list& masses) {
        for (size_t i = 0; i < len(masses); i++) {
            double mass = boost::python::extract<double>(masses[i]);
            stars.push_back(Star(mass));
        }
    }

    bool update(int star_number, double mass) {
        return this->stars[star_number].set_mass(mass);
    }

private:
    std::vector<Star> stars;
};

BOOST_PYTHON_MODULE(galaxy)
{
    using namespace boost::python;
    class_<Galaxy>("Galaxy", init< boost::python::list >())
        .def("update", &Galaxy::update)
    ;
}

setup.py :請注意,Boost已使用Macports安裝在我的機器上; 您可能需要在include_dirs變量中調整可以找到它的路徑。

from distutils.core import setup
from distutils.extension import Extension

setup(name="galaxies",
      ext_modules=[
          Extension(
              "galaxy", ["galaxy.cpp"],
              include_dirs=["/opt/local/include"],
              libraries=["boost_python-mt"])])

最后,使用Galaxy對象在main.py執行所需的任何main.py 請注意,在此示例中,該對象是通過Python列表構建的(這意味着您實際上實際上是在Python和C ++之間至少傳遞了一次數組),但這不是必須的:您可以讓C ++代碼讀取數據文件,並通過Python傳遞其路徑。

import galaxy

sombrero = galaxy.Galaxy([0.1, 22.3, 33.4])
sombrero.update(0, 24.5)

這是編譯和運行示例的方法:

$ python setup.py build_ext --inplace && python main.py

總是這樣:

http://www.boost.org/doc/libs/1_55_0/libs/python/doc/

“歡迎使用Boost.Python版本2,該版本是一個C ++庫, 在C ++和Python編程語言之間實現無縫的互操作性 。”

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM