【问题标题】:How to convert python array to cython array?如何将python数组转换为cython数组?
【发布时间】:2012-07-26 06:14:00
【问题描述】:

我有一个在常规 Python 中创建的浮点值数组,我想将其传递给底层 C 函数前面的 cython 函数。 C 函数要求数组作为浮动指针传递,如下所示:

void setOverlays(const float * verts);

cython 包装器如下所示:

def set_overlays(verts):
    setOverlays(verts)

如何将 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)))

我正在尝试实现同样的目标,但在 cython 中

提前致谢!

【问题讨论】:

标签: python arrays cython


【解决方案1】:

我相信您可以通过迭代浮点数的 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)

【讨论】:

【解决方案2】:

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

@JAB 的答案说明了要走的路,但我想详细说明。

传递一个数组:

问题是如何将 python 数组转换为 c 样式的数组。 Python array(来自array 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

【讨论】:

  • 这可以在 cython 纯模式下通过常规 python 代码完成吗?
  • @Jay 我不明白你的问题。您可以在 def 或 cdef 函数中执行此操作。
【解决方案3】:

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

【讨论】:

  • 不幸的是 Cython-0.15 不支持 C99 可变长度数组。我还没有检查 Cython-0.16。
  • 啊,我明白了。 ...很高兴看到它终于支持 Python 3.x,不过,上次我想尝试 Cython 时并非如此。
【解决方案4】:

这是我用来准备数组以传递给 Cython 或带有 SWIG 的 C/CPP。

import numpy as np    
def make_c_array(a):
    """
    Take an input numpy array and convert to being ready for use in C.
    """
    b = []
    for i in range(len(a)):
        b.append(a[i])
    a = np.array(b,dtype=np.dtype('d'),order='C')
    return a

【讨论】:

    【解决方案5】:

    我找到了 Cython 特有的方式:

    cdef float* cVerts = []
        for i in xrange(len(verts)):
            cVerts[i] = verts[i]
    setOverlays(cVerts)
    

    有趣的是,上述两种解决方案都被 cython 编译器拒绝了。

    【讨论】:

    • 我认为这是不正确的——您从未指定过 cVerts 的大小,我很确定您稍后需要释放该内存。当它实际运行时,您充其量只能写入随机内存。如果您有一个文档链接,否则我很想看看它,因为 Cython 在编译时需要解释许多困难的事情(我认为它不会做这些事情)。
    • 由于 malloc 的导入语句中的拼写错误,编译器拒绝了它。再次尝试“EfForEffort”答案,它应该可以工作。
    • 您可能想要使用类似 cdef float cVerts[len(verts)] 的解决方案,因为您的解决方案似乎只是覆盖了内存(注意分段错误!)
    猜你喜欢
    • 1970-01-01
    • 2023-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-03
    • 2021-12-24
    • 2014-01-25
    相关资源
    最近更新 更多