Kir*_*ril 9 python arrays cython
我有一个在常规Python中创建的float值数组,我想传递给一个cython函数,该函数用于底层C函数.C函数要求将数组作为浮动指针传递,如下所示:
void setOverlays(const float * verts);
Run Code Online (Sandbox Code Playgroud)
cython包装器看起来像这样:
def set_overlays(verts):
setOverlays(verts)
Run Code Online (Sandbox Code Playgroud)
如何将verts变成cython数组呢?我认为这可能有效:
cdef float * cVerts = [v for v in verts]
Run Code Online (Sandbox Code Playgroud)
但不幸的是,生成的值是一个Python对象,在这种情况下,自动转换不起作用.
ctypes中的等效表达式(有效)是:
cVerts = (c_float * len(verts))()
for i in range(len(verts)):
cVerts[i] = verts[i]
setOverlays(cast(byteref(cVerts), POINTER(c_float)))
Run Code Online (Sandbox Code Playgroud)
我试图实现同样的目标,但在cython中
提前致谢!
我相信你可以通过迭代浮点数的python列表并将它们放在一个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)
Run Code Online (Sandbox Code Playgroud)
float *接受的答案是错误的,会导致分段错误,因为从未分配过内存。
@JAB 的答案显示了要走的路,但我想详细说明一下。
传递一个数组:
问题是如何将Python数组转换为C风格数组。Python array(来自arraymodule)是连续内存的包装器,因此不需要复制内存 - 我们只需将指针传递给 c 函数即可:
from cpython cimport array
import array
def set_overlays(array.array verts):
setOverlays(verts.data.as_floats)
Run Code Online (Sandbox Code Playgroud)
使用array模块比使用模块更好,numpy因为它是标准库的一部分 - 无需安装任何东西。这个解决方案简短而漂亮,但有一个问题:有人可以将它与 an 一起使用int-array,并且不会出现错误 - 内存只是被重新解释。有时这是人们想要的,但大多数时候情况并非如此。
为了确保传递的数组对象具有正确的数据类型,可以使用内存视图:
from cpython cimport array #still needed
def set_overlays_memview(float[::1] verts):
setOverlays(&verts[0])
Run Code Online (Sandbox Code Playgroud)
[::1] 确保内存视图环绕连续内存。但是,如果内存视图中没有元素,则由于越界访问,此代码会出现问题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
Run Code Online (Sandbox Code Playgroud)
Kir*_*ril -2
我找到了 Cython 的具体方式:
cdef float* cVerts = []
for i in xrange(len(verts)):
cVerts[i] = verts[i]
setOverlays(cVerts)
Run Code Online (Sandbox Code Playgroud)
有趣的是,上述两个解决方案都被 cython 编译器拒绝。