使用C ++和Python访问数组

时间:2014-05-12 08:31:36

标签: python c++ arrays

我正在研究一个由大约10万颗恒星组成的迷你星系。我想用Python做的可视化表示,C ++中的大型计算。使用ctypes,我可以从Python调用C ++函数。

我基本上想要的是RAM中的数组,可以通过python和C ++访问。然后在python中调用函数update()时,C ++更新数组。重要的是C ++实际上只改变了数组中的值。一直复制它会非常耗时。

我是一个初学者,特别是在C ++中,所以我真的不知道在哪里可以找到正确的信息,以及使用哪些关键字。关于如何做到这一点的想法当然是受欢迎的,但一些信息链接也将受到高度赞赏。

最佳,

5 个答案:

答案 0 :(得分:1)

您可以使用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)
    ...

答案 1 :(得分:1)

您应该完全检查有关此问题的Python文档:

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

记住doc,你可以定义一个新的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文档来实现new,alloc,dealloc和init方法(这些非常简单)并且完成了!

答案 2 :(得分:1)

正确地执行此操作实际上非常复杂。首先你 应该在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支持。

答案 3 :(得分:1)

以下是另一个关于如何使用Boost.Python完成此任务的提案。

让我们用3个文件组织代码:一个setup.py来处理编译扩展代码,一个只使用扩展代码的Python脚本,以及扩展代码本身:

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

galaxy.cpp:请注意,不处理异常,因此您可以通过分配尚未初始化的Star和其他C ++奇怪来产生分段错误。如果您修改此代码,请注意始终将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:请注意,使用Macports已经在我的机器上安装了Boost;您可能需要在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中执行您需要的任何操作。请注意,在此示例中,对象是从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

答案 4 :(得分:0)

总有这个:

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

&#34;欢迎使用Boost.Python的第2版,这是一个C ++库,实现了C ++与Python编程语言之间的无缝互操作性。&#34;