9

我正在将 Cython 包装器写入 C 函数。我有一个带有以下签名的 pxd 文件:

double contr_hrr(int lena, double xa, double ya, double za, double *anorms)

当我尝试从 pyx 文件中调用它时

...
return contr_hrr(len(acoefs),a.origin[0],a.origin[1],a.origin[2],anorms2)

其中anorms2是一个 python 列表,我收到错误消息:

cython/ctwo.pyx:35:80: Cannot convert Python object to 'double *'

如何将 python 列表作为双数组传递给 C 函数?

4

3 回答 3

9
  1. 进口array

    from cpython cimport array
    
  2. 从您的列表中创建一个数组对象。数组类构造函数将完成所有繁重的分配内存和迭代列表的工作(实际上可以是任何可迭代的)。

    cdef array.array anorms2_arr = array.array('d', anorms2)
    
  3. 将其数据传递给您的函数:

    return contr_hrr(.., anorms2_arr.data.as_doubles)
    

array是一个标准的 Python 模块。Cython 在顶部添加了一些特殊支持,例如缓冲区接口和通过arr.data.as_xxx. 不幸的是,这种支持只记录在这里。您还可以在这个最近的线程中找到有关数组使用的一些详细信息。

于 2013-06-09T23:02:29.790 回答
4

我认为你不能这样做,而是自己转换它:

cimport cython
from libc.stdlib cimport malloc, free

...
cdef double *anorms
cdef unsigned int i;

anorms = <double *>malloc(len(anorms2)*cython.sizeof(double))
if anorms is NULL:
    raise MemoryError()

for i in xrange(len(anorms2)):
    anorms[i] = anorms2[i]

return contr_hrr(len(acoefs),a.origin[0],a.origin[1],a.origin[2],anorms)

如果你使用过 C++,情况会有所不同,因为

The following coercions are available:
Python type   =>   C++ type             => Python type
bytes              std::string             bytes
iterable           std::vector             list
iterable           std::list               list
iterable           std::set                set
iterable (len 2)   std::pair               tuple (len 2)

如果您可以切换到 C++,您将可以直接转换List[float]vector<double>

from libcpp.vector cimport vector

def py_contr_hrr(vector[double] anorms2, ...):
    ...
    return contr_hrr(len(acoefs),a.origin[0],a.origin[1],a.origin[2],anorms2)

并直接从 Python 端调用:

anorms2 = [12.0, 0.5, ...]
py_contr_hrr(anorms2, ....)

来源:http ://docs.cython.org/src/userguide/wrapping_CPlusPlus.html#standard-library

但我不知道这是否是您可以考虑的选择...当然,这取决于您项目的限制。

编辑:我不知道Nikita' 的做事方式(顺便说一句,这是一种优雅的方式),而且我不知道哪种方式最适合大型阵列的表演。

于 2013-06-09T22:55:03.083 回答
2

我最终所做的是确保异常数组在代码的 python 部分中作为数组维护,然后按照 Nikita 的配方使用 .data.as_doubles 属性将它们即时转换为双精度数。如果我这样做,与在 C 中本地执行所有操作相比,它的开销似乎很小。

由于各种平凡的原因,尚未尝试过 numpy 方法。

于 2013-06-14T10:01:31.603 回答