Affichez les données C / C ++ comme np.array à partir de Python.
struct Particle {
float x[3], v[3];
};
vector<Particle> v;
Et supposons que des données telles que «Particle *» se trouvent du côté C / C ++.
numpy.array from C/C++
Tout d'abord, incluez numpy / arrayobject.h
et initialisez-le. Cela semble initialiser une variable statique, et si vous avez plus d'un code source, vous devez appeler ʻimport_array () `dans tout le code source qui utilise numpy. Sinon, vous obtiendrez une erreur de segmentation.
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
#include "numpy/arrayobject.h"
PyMODINIT_FUNC
PyInit_cext07(void) {
import_array();
return PyModule_Create(&module);
}
Définissez ʻinclude_dirs dans
setup.py` pour lire l'en-tête NumPy.
import numpy as np
from distutils.core import setup, Extension
setup(name='cext07',
version='0.0.1',
description='c_ext07 read data as np.array',
author='Jun Koda',
url='https://github.com/junkoda/python_c_ext',
ext_modules=[
Extension('cext07', ['cext07.c'],
include_dirs = [np.get_include()]),
],
)
Une fonction qui passe un pointeur vers vector <Particle>
afin qu'il puisse être référencé du côté Python:
static void py_particles_free(PyObject *obj);
static PyObject* py_particles_alloc(PyObject *self, PyObject *args)
{
// Allocate a new C++ pointer as a Python object "_Particles"
vector<Particle>* const p= new vector<Particle>();
p->resize(10); //En supposant que les données contiennent 10 particules
return PyCapsule_New(p, "_Particles", py_particles_free);
}
void py_particles_free(PyObject *obj)
{
// Destructor function for _Particles pointer, called automatically from Python
vector<Particle>* const p=
(vector<Particle>*) PyCapsule_GetPointer(obj, "_Particles");
delete p;
}
Une fonction qui passe vector <Particle>
comme np.array
:
PyObject* py_as_array(PyObject *self, PyObject *args)
{
PyObject* py_particles;
if(!PyArg_ParseTuple(args, "O", &py_particles))
return NULL;
// Get vector<Particle>* pointer back from _Particles
vector<Particle>* const p=
(vector<Particle>*) PyCapsule_GetPointer(py_particles, "_Particles");
if(!p) return NULL;
int nd=2; //Tableau à deux dimensions avec des lignes et des colonnes
int ncol= sizeof(Particle)/sizeof(float); // ncol=6 x[3], v[3]6 rangs
npy_intp dims[]= {(npy_intp) p->size(), ncol};
return PyArray_SimpleNewFromData(nd, dims, NPY_FLOAT, &(p->front()));
}
Fonctions d'extension C / C ++ usuelles
static PyMethodDef methods[] = {
{"_particles_alloc", py_particles_alloc, METH_VARARGS, "new Particles"},
{"_as_array", py_as_array, METH_VARARGS, "vector<Particle> as an array"},
{NULL, NULL, 0, NULL}
};
static struct PyModuleDef module = {
PyModuleDef_HEAD_INIT,
"cext07", // name of this module
"Use vector<Particle>", // Doc String
-1,
methods
};
import numpy as np
import cext07
class Particles:
def __init__(self):
self._p= cext07._particles_alloc() # _Pointeur de particules
def __repr__(self):
return cext07._as_array(self._p).__repr__()
def __getitem__(self, index):
return cext07._as_array(self._p)[index]
def asarray(self):
return cext07._as_array(self._p)
#etc
import cext07
p = Particles()
p # __repr__Voit le tableau par
p[0] # __getitem__;Première particule
p[2:5,2] #tranche est aussi np.le tableau le gère
p[:,0] # x[0]
p[:,4] # v[1]
p[:] #Toutes les données
Dans cet exemple, nous n'avons besoin d'aucune classe Python, juste de la fonction as_array. Je vais simplifier plus tard.
Le code complet peut être trouvé sur GitHub.
Recommended Posts