我需要通过python C API创建一个新列表,其中包含我编写的Quaternion
类的对象的新副本(在C ++中)。 [实际上,I'd really like a numpy array,但任何类型的序列都可以。但是我遇到了我尝试过的所有事件的段错误。我的指针非常糟糕,所以这并不是什么大惊喜。我想也许我需要使用new
来创建我创建的对象的python所有权。
我到目前为止所获得的最好成绩如下。我不应该在new
时复制构造四元数吗?我在做别的蠢事吗?我现在需要告诉python它拥有引用吗?返回的列表是否应该存在,并且像我预期的那样过上幸福的生活?
PyObject* Objectify(std::vector<Quaternion>& v) {
Py_ssize_t size = v.size();
PyArrayObject* list = (PyArrayObject*) PyList_New(size);
for(Py_ssize_t i=0; i<size; ++i) {
PyObject* o = (PyObject*) new Quaternion(v[i]);
PyList_SET_ITEM((PyObject*)list, i, o);
}
return PyArray_Return(list);
}
我可以在返回之前验证列表是否仍具有正确的元素。也就是说,在上面的循环之后,我创建一个新循环并打印出列表值旁边的原始值,它们匹配。该函数将返回,我可以继续使用python。但是一旦在循环外部使用列表,就会发生段错误。
[实际上,这一切都是在SWIG中完成的,这个代码可以在变量名称略有不同的类型映射中找到,但是我可以查看_wrap.cxx
文件,看看它是怎么样的写下来。]
答案 0 :(得分:1)
现在我明白了,很明显。我不能将任意类型转换为PyObject
;它需要实际上有一些实际的python结构。例如,我认为PyArrayObject
可以这样投射,但我的随机类需要包装,正如dastrobu在other question上解释的那样。
正如我所提到的,我正在使用SWIG,它已经将Quaternion
包装到某种PyObject
中(虽然它给出了一些其他名称来表示它是由SWIG制作的)。所以,虽然这一般不能回答我的问题,但以下内容正是我所需要的(包括创建numpy数组,而不仅仅是列表):
npy_intp size = v.size();
PyArrayObject *npy_arr = reinterpret_cast<PyArrayObject*>(PyArray_SimpleNew(1, &size, NPY_OBJECT));
PyObject** data = static_cast<PyObject**>(PyArray_DATA(npy_arr));
for(npy_intp i=0; i<size; ++i) {
PyObject* qobj = SWIG_NewPointerObj((new Quaternions::Quaternion(v[i])),
SWIGTYPE_p_Quaternions__Quaternion, SWIG_POINTER_OWN);
if(!qobj) {SWIG_fail;}
data[i] = qobj;
Py_INCREF(qobj);
}
我还应该指出,我最初尝试使用PyArray_SET_ITEM
在此代码中分配列表中的项目,但不断获取段错误,这就是我使用这种奇怪方法的原因。我想知道它是否与NPY_OBJECT
...
无论如何,我希望将来帮助别人。