Skip to main content
 首页 » 编程设计

python之python C API 中新自定义类对象的返回列表

2025年05月04日8sxdcgaq8080

我需要通过 python C API 创建一个新列表,其中包含我编写的(C++ 中)Quaternion 类对象的新副本。 [实际上,I'd really like a numpy array ,但任何顺序都可以。] 但是我尝试过的所有操作都遇到段错误。我对指针很糟糕,所以这并不奇怪。我在想,也许我需要让 python 拥有我用 new 创建的对象。

我迄今为止获得的最好成绩如下所示。我不应该在 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 文件,发现它是我会怎么写它。]

请您参考如下方法:

现在我看到了,这是显而易见的。我不能将任意类型转换为 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...

的偏移量有关

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