2

I need to create a new list via the python C API containing new copies of objects of a Quaternion class I've written (in C++). [Actually, I'd really like a numpy array, but any sort of sequence would do.] But I'm getting seg faults with everything I've tried. I'm terrible with pointers, so that's not a big surprise. I'm thinking maybe I need to give python ownership of the objects I create with new.

The best I've gotten so far appears below. Am I not supposed to copy-construct the Quaternion while newing it? Am I doing something else stupid? Do I need to tell python it owns the reference now? Should the returned list exist and live a happy life, as I expected?

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);
}

I can verify that the list still has the correct elements just before the return. That is, after the loop above, I make a new loop and print out the original values next to the list values, and they match. The function will return, and I can keep using python. But once the list is used outside the loop, the segfaults happen.

[Actually, this is all being done in SWIG, and this code is found in a typemap with slightly different variable names, but I can look in the _wrap.cxx file, and see that it's just how I would have written it.]

4

1 回答 1

1

现在我看到了,这很明显。我不能将任意类型转换为PyObject; 它实际上需要有一些实际的 python 结构。例如,我认为 aPyArrayObject可以这样转换,但我的随机类需要被包装,正如 dastrobu 在我的另一个问题中解释的那样。

正如我所提到的,我正在使用 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...的偏移量有关

无论如何,我希望这对将来的其他人有所帮助。

于 2013-10-23T14:13:32.310 回答