[英]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.