使用C API创建自定义类对象的numpy数组 [英] Creating a numpy array of custom-class objects with C API
问题描述
我想使用C API创建一个numpy数组,其中包含类型为Quaternion
的对象,这是我用C ++编写的类.我已经有一个这样的数组(实际上是一个std::vector
),并且我想进行复制-或在可能的情况下使用相同的内存.
Using the C API, I would like to create a numpy array containing objects of type Quaternion
, which is a class I've written in C++. I already have an array of these (actually a std::vector
), and I want to make a copy -- or use the same memory if possible.
由于这不是基本类型,因此我需要使用Py_Object
类型,并且不能使用PyArray_SimpleNew
或类似的简单方法.
Since this isn't a basic type, I need to use Py_Object
types, and can't use PyArray_SimpleNew
or anything easy like that.
我猜我可能想使用PyArray_NewFromDescr
甚至PyArray_SimpleNewFromDescr
,但是我完全无法理解如何创建PyArray_Descr
对象,我需要描述我的Quaternion类.
I'm guessing I might want to use PyArray_NewFromDescr
or even PyArray_SimpleNewFromDescr
, but I am completely and utterly lost as to how I might create the PyArray_Descr
object I need to describe my Quaternion class.
任何人都可以给我一些有关如何制作该descr对象的指示吗?还是让我对如何构造numpy数组有一个更好的主意?
Can anyone give me some pointers about how to make that descr object? Or give me a better idea of how to construct my numpy array?
这基本上是这个问题,没有干扰.
This is basically a more general version of this question, without the distractions.
使用dastrobu的提示以及我的SWIG包装程序,我找到了一种方法.我知道不是每个人都在使用SWIG,但是对于那些正在使用SWIG的人,我对其他问题的回答显示了我的工作方式
Using dastrobu's hint, and my SWIG wrapper, I found a way to do it. I know that not everyone is using SWIG, but for those who are, my answer on my other question shows how I worked it out.
推荐答案
由于Quaternion
不是直接数字类型,因此您的数组必须具有numpy.object
作为dtype
.因此,您可以使用PyArray_SimpleNew(..., NPY_OBJECT)
创建一个数组并填写数据.
问题是您的Quaternion
类不是python类型.因此,使用对类型为Quaternion
的对象的引用填充数组将不起作用. (在这种情况下,如果您从python中填充了四元数的数组中提取一个元素,将会发生什么?)
相反,您需要用PyQuaternion
之类包装Quaternion
类.包装器负责引用计数和内存管理.看起来像这样:
Since Quaternion
is not directly a numeric type, your array must have numpy.object
as dtype
. Hence, you can use PyArray_SimpleNew(..., NPY_OBJECT)
to create an array and fill in the data.
The problem is that your Quaternion
class is not a python type. So filling the array with references to objects of type Quaternion
will not work. (In this case, what would you expect to happen, if you extract an element from the array filled with quaternions from python?)
Instead, you need to wrap the Quaternion
class with something like PyQuaternion
. The wrapper takes care of reference counts and memory management. It will look something like:
typedef struct {
PyObject_HEAD
Quaternion *q;
}PyQuaternion;
static PyTypeObject PyQuaternion_Type = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"Quaternion", /*tp_name*/
sizeof(PyQuaternion), /*tp_basicsize*/
/* ... */
};
static PyObject *
PyQuaternion_new(PyTypeObject *type, PyObject *args, PyObject *kwds){
/* ... */
};
static int
PyQuaternion_init(PyQuaternion *self, PyObject *args, PyObject *kwds){
/* ... */
};
static void PyQuaternion_dealloc(PyQuaternion *self){
/* ... */
};
此外,您可以为PyQuaternionType
定义自己的C-API,从而可以从Quaternions
Furthermore you can define your own C-API for the PyQuaternionType
allowing you to create PyQuaternions
from Quaternions
static PyObject *
PyQuaternion_New(Quaternion *q){
PyQuaternion *self;
self = (PyQuaternion *)PyQuaternion_Type.tp_new(type, NULL, NULL);
self->q = q;
return (PyObject *)self;
}
请注意,self->q
将由PyQuaternion_dealloc
函数处理,因此请考虑内存管理.最简单的方法是将所有权传递给包装器,然后让PyQuaternion_dealloc
释放self->q
.
Be aware that self->q
will be handled by the PyQuaternion_dealloc
function, so think about the memory management. The simplest would be to pass ownership to the wrapper and let PyQuaternion_dealloc
deallocate self->q
.
PyQuaternion_New
函数允许您包装Quaternion
对象并将其填充到任何python容器中,例如列表,元组,当然还有带有dtype = numpy.object
的numpy数组.
The PyQuaternion_New
function allows you to wrap Quaternion
objects and fill them in to any python container, like lists, tuples and of course also numpy arrays with dtype = numpy.object
.
这篇关于使用C API创建自定义类对象的numpy数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!