如何将Python数组转换为Cython数组?

2024-05-04 21:45:20 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个用普通Python创建的浮点值数组,我想把它传递给一个cython函数,该函数面向底层C函数。 C函数要求将数组作为浮动指针传递,如下所示:

void setOverlays(const float * verts);

cython包装看起来像这样:

def set_overlays(verts):
    setOverlays(verts)

我怎样才能把顶点变成一个cython数组? 我想这可能管用:

cdef float * cVerts = [v for v in verts]

但不幸的是,生成的值是一个Python对象,在这种情况下,自动转换不起作用。

ctypes中的等效表达式(有效)是:

cVerts = (c_float * len(verts))()
for i in range(len(verts)):
    cVerts[i] = verts[i]
setOverlays(cast(byteref(cVerts), POINTER(c_float)))

我也在努力实现同样的目标,但是在赛顿

提前谢谢!


Tags: 函数inforlen面向数组floatcython
3条回答

我相信您可以通过迭代python的float列表并将它们放入C数组中来实现这一点。

cimport cython
from libc.stdlib cimport malloc, free

cdef:
    float * cfloats
    int i

cfloats = <float *> malloc(len(pyfloats)*cython.sizeof(float))
if cfloats is NULL:
  raise MemoryError()
for i in xrange(len(pyfloats)):
  cfloats[i] = pyfloats[i]
setOverlays(cfloats)
free(cfloats)

接受的答案是错误的,并导致分段错误,因为float *的内存从未分配。

“JAB”的答案指明了前进的方向,但我想详细说明一下。

传递数组:

问题是如何将python数组转换为c样式的数组。Pythonarray(来自^{} module)是连续内存的包装器,因此不需要复制内存-我们只需将指针传递给c函数:

from cpython cimport array
import array

def set_overlays(array.array verts):
    setOverlays(verts.data.as_floats)

使用array模块比numpy更好,因为它是标准库的一部分-不需要安装任何东西。这个解决方案很短也很好,但是有一个问题:有人可以用int-array来使用它,并且不会出现错误-内存只是被重新解释了。有时这是一个人想要的,但大多数情况下不是这样。

为了确保传递的数组对象具有正确的数据类型,可以使用内存视图:

from cpython cimport array #still needed

def set_overlays_memview(float[::1] verts):
    setOverlays(&verts[0])

[::1]ensures,内存视图环绕连续内存。但是,如果内存视图中没有元素,这段代码就有问题,因为有越界访问verts[0]。正确的处理方法取决于函数setOverlays,而不是这个答案的一部分。

传递列表:

如果必须将python列表传递给c函数,则必须将值复制到连续内存中。最好使用array的功能-无需重新设计轮子:

from cpython cimport array
import array

def set_overlays_list(list verts):
    cdef array.array a =  array.array('f', verts)
    setOverlays(a.data.as_floats) #we already know they are floats

签出http://docs.cython.org/src/userguide/memoryviews.html。看起来它还提供了如何利用Python内置的array模块以及numpy的提示。

相关问题 更多 >