Python C API 读取列表的列表,分配内存和全局变量
我正在写一个模块,目的是优化一个操作,但我有几个问题。
首先
我需要把一个数组(也就是一个列表的列表)从Python传到C,我是这样做的:
long i_k;
for (int k = 0; k < n; k++) {
PyObject *first = PyList_GetItem(streamMatrixObj, k);
for (int i = 0; i < n; i++) {
PyObject *second = PyList_GetItem(first, i);
i_k = PyLong_AsLong(second);
f[k][i] = i_k;
}
}
这个矩阵的大小总是 n x n
。有没有更好的方法来读取和存储这个列表到C的数组里呢?
其次
我为C数组分配内存是这样做的:
void **createMatrix(uint rows, uint cols) {
long **matrix;
const size_t row_pointers_bytes = rows * sizeof(*matrix);
const size_t row_elements_bytes = cols * sizeof(**matrix);
matrix = PyObject_Malloc(row_pointers_bytes + rows * row_elements_bytes);
if (!matrix) {
PyErr_NoMemory();
return NULL;
}
size_t i = 0;
long *data = matrix + rows;
for (i = 0; i < rows; i++)
matrix[i] = data + i * cols;
return matrix;
}
我应该用 PyMem_Malloc
还是 PyObject_Malloc
呢?我在这个问题里看到了一些解释:
但我还是不太清楚该用哪个函数。
第三
这个模块的方法会被调用很多次,所以我想把C数组保留在内存中,以避免每次都重新创建数组。比如说,我会从Python调用这个方法 myModule.deltaC(1,2,[1,2,3])
,这个调用会对矩阵进行一些操作。
我能不能在使用 deltaC
函数之前先初始化数组,比如用 myModule.initMatrix([[1,2,3],[1,2,3], [1,2,3]])
,然后把它保留在内存中直到程序结束?那么这个C数组就需要在模块里作为一个全局变量吗?
更新
我试着用 module.initMatrix
在全局变量中初始化C数组,但当调用 module.delta
时,访问C数组时出现了段错误(SegFault),所以我想这可能是不行,或者我遗漏了什么。
第四
有没有办法检测到Python程序结束,以便调用 PyObject_free(array)
来释放为C数组分配的内存?
1 个回答
首先:这基本上就是应该怎么做。
其次:我理解你应该在这里使用 PyMem_Malloc
和 PyMem_Free
。而 PyObject_Malloc
和 PyObject_Free
是专门用来分配Python对象的,特别适合处理很多小对象。不过,除非你分配了大量内存或者进行了非常多的分配,否则这两者之间的区别并不会太大。
第三和第四:你可以使用 Capsules API 来存储你的C结构,并在API函数之间传递它们。与其存储一个全局矩阵,不如让你的初始化函数(initMatrix)返回一个包含矩阵的胶囊,然后把这个胶囊传递给其他函数(比如deltaC)。当这个矩阵不再被引用时,它会自动被销毁。
如果你只打算存储矩阵,另一种可能的选择是使用 numpy 数组。这些数组可以通过 numpy C API 直接在C语言中作为矩阵访问。这样你就不需要调用Python的C API函数来获取矩阵的每个元素,也不需要自己分配内存或在矩阵被销毁时手动释放内存。