我正在为C函数编写一个Cython包装器。我有一个带有以下签名的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函数?
答案 0 :(得分:8)
cimport array
:
from cpython cimport array
从列表中创建一个数组对象。数组类构造函数将执行所有繁重的重组分配内存并迭代您的列表(实际上可以是任何迭代)。
cdef array.array anorms2_arr = array.array('d', anorms2)
将其数据传递给您的函数:
return contr_hrr(.., anorms2_arr.data.as_doubles)
array
是standard Python module。 Cython在顶部添加了一些特殊支持,如缓冲区接口和通过arr.data.as_xxx
直接访问底层内存块。不幸的是,此支持仅记录here。
您还可以在this recent thread中找到有关数组使用情况的一些详细信息。
答案 1 :(得分: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
的做法(顺便说一下,这是一个优雅的做法),我不知道以哪种方式最适合大表演阵列。
答案 2 :(得分:2)
我最终做的是确保将anorms数组维护为代码的python部分中的数组,然后使用Nikita的配方将它们动态转换为使用.data.as_doubles属性的双精度数。如果我这样做,与在C中本地执行任何操作相比,它似乎只有很少的开销。
由于各种普通的原因,尚未尝试采用numpy方法。