在Python / C API中的PyObject_CallObject中传递动态数组作为参数

问题描述

我想访问一些我用C代码编写的python函数。我的python函数之一接收一个numpy数组作为输入。在我的C代码中,此数组分配在动态内存中。每当我的python函数调用时,我都会收到一个分段错误,而且我不确定自己在做什么错。我试图将N,O,O&传递给Py_BuildValue函数,但我一直得到相同的结果。

这是python的简化代码

#Python simple function that receives pointer to array
#!/usr/bin/python3

import numpy as np
def getNumpyArrayPointer(pointer):
    data = np.ctypeslib.as_array(pointer,shape=(1000,1)).astype(np.int32) #Doesn't matter if I comment out this line. Fault continues
    print('Python function getNumpyArrayPointer() called')
    return data

这是C简化代码

#include <iostream>
#include <Python.h>
#include "pyhelper.h"


int capitest()
{
    Py_Initialize();
    PyObject* sysPath = PySys_Getobject((char*)"path");
    PyObject* programName = PyUnicode_FromString("path-to-python-script");
    PyList_Append(sysPath,programName);
    Py_DECREF(programName);
    PyObject* pName = PyUnicode_FromString("python-script-name");
    PyObject* pModule = PyImport_Import(pName);
    PyObject* pValue;
    cpyObject pFunc;
    PyObject* args;

    if(pModule)
    {
        pFunc = PyObject_GetAttrString(pModule,"getNumpyArrayPointer");
        uint32_t *array = (uint32_t *)malloc (1000);
        args = Py_BuildValue("(N)",array );
        
        if(pFunc && PyCallable_Check(pFunc))
        {
            printf("Calling getNumpyArrayPointer\n");
            pValue = PyObject_CallObject(pFunc,args);
            Py_DECREF(args);
            printf("Called getNumpyArrayPointer\n");
            if (PyErr_Occurred()) 
            { 
                PyErr_Print(); 
                return 0; 
            }   
        }
        else
        {
            printf("ERROR: function getNumpyArrayPointer()\n");
        }
    }
    else
    {
        printf("ERROR: Module not imported\n");
    }
    Py_Finalize();
    return 0;
}

int main()
{
    capitest();
}

输出

Calling getNumpyArrayPointer
Segmentation fault (core dumped)

解决方法

 uint32_t *array = (uint32_t *)malloc (1000);
 args = Py_BuildValue("(N)",array );

那是胡扯。您要告诉它数组是指向Python对象的指针,因此它将尝试管理数组的“引用计数”。

我会提出一些建议:

PyObject* pointer_as_int = PyLong_FromVoidPtr(array);

然后,您要将其传递给ctypes.cast(pointer_as_int,ctypes.POINTER(ctypes.c_uint32))的Python对象以获取ctypes指针。例如参见ctypes: construct pointer from arbitrary integer

或者,您可以尝试直接将C指针传递给Numpy C API函数PyArray_SimpleNewFromData-您会在Stack Overflow和其他地方找到很多示例。


请注意,一旦完成处理,您的C代码将负责释放数组。