从Cdef函数返回数组

时间:2015-11-26 11:39:30

标签: python arrays cython

我想在c风格中创建一个纯函数,它将数组作为参数(指针)并用它做一些事情。但我无法找到如何为cdef函数定义数组参数。这是我制作的一些玩具代码。

cdef void test(double[] array  ) except? -2:
  cdef int i,n
  i = 0
  n = len(array)
  for i in range(0,n):
     array[i] = array[i]+1.0



def ctest(a):
   n = len(a)
   #Make a C-array on the heap.
   cdef double *v
   v = <double *>malloc(n*sizeof(double))
   #Copy in the python array
   for i in range(n):
      v[i] = float(a[i])
   #Calling the C-function which do something with the array
   test(v)
   #Puttint the changed C-array back into python
   for i in range(n):
      a[i] = v[i]
   free(v)
   return a

代码无法编译。已经搜索了如何在Cython中定义C数组,但还没有找到如何做到这一点。 double []数组显然不起作用。也尝试过:

cdef void test(double* array  ) except? -2:

我可以设法在纯c中做同样的事情,但不能在cython中做同样的事情:(

   D:\cython-test\ python setup.py build_ext --inplace
   Compiling ctest.pyx because it changed.
   [1/1] Cythonizing ctest.pyx

   Error compiling Cython file:
   ------------------------------------------------------------
   ...
   from libc.stdlib cimport malloc, free

   cdef void test(double[] array):
       cdef int i,n
       n = len(array)
                   ^
   ------------------------------------------------------------

   ctest.pyx:5:17: Cannot convert 'double *' to Python object

   Error compiling Cython file:
   ------------------------------------------------------------
   ...
   from libc.stdlib cimport malloc, free

   cdef void test(double[] array):
       cdef int i,n
       n = len(array)
       for i in range(0,len(array)):
                                ^
   ------------------------------------------------------------

   ctest.pyx:6:30: Cannot convert 'double *' to Python object
   Traceback (most recent call last):
     File "setup.py", line 10, in <module>
       ext_modules = cythonize("ctest.pyx"),
     File "C:\Anaconda\lib\site-packages\Cython\Build\Dependencies.py", line           877, i
   n cythonize
       cythonize_one(*args)
     File "C:\Anaconda\lib\site-packages\Cython\Build\Dependencies.py", line 997, i
   n cythonize_one
       raise CompileError(None, pyx_file)
   Cython.Compiler.Errors.CompileError: ctest.pyx

   E:\GD\UD\Software\BendStiffener\curvmom>

更新

在所有建议之后更新了我的代码并且它现在编译:)但我的数组仍然没有更新。我希望所有条目都应该用5.0更新,但它们不会

from libc.stdlib cimport malloc, free

cdef void test(double[] array):
    cdef int i,n
    n = sizeof(array)/sizeof(double)
    for i in range(0,n):
        array[i] = array[i]+5.0

def ctest(a):
    n = len(a)
    #Make a C-array on the heap.
    cdef double* v
    v = <double*>malloc(n*sizeof(double))
    #Copy in the python array
    for i in range(n):
        v[i] = float(a[i])
    #Calling the C-function which do something with the array
    test(v)
    #Puttint the changed C-array back into python
    for i in range(n):
        a[i] = v[i]
    free(v)
    for x in a:
        print x
    return a

这是一个用于测试我的代码的python测试程序:

import ctest
a = [0,0,0]
ctest.ctest(a)

所以我仍然做错了。有什么建议吗?

2 个答案:

答案 0 :(得分:0)

len()是一个python函数,仅适用于python对象。这就是为什么它不会编译。 对于C阵列,您可以将n=len(array)替换为n = sizeof(array) / sizeof(double)

答案 1 :(得分:0)

您可能需要查看typed memoryviews和缓冲区界面。这些为数组提供了一个很好的接口,比如那些基于numpy数组的数据结构,但也可以用来处理C数组。来自文档:

  

例如,他们可以处理C数组和Cython数组类型(Cython arrays)。

在您的情况下,这可能有所帮助:

cdef test(double[:] array) except? -2:
    ...

double[:]允许将所有1d双数组传递给函数。那些可以修改。由于[:]定义了一个内存视图,所有更改都将在您创建内存视图的数组中进行(您作为参数传递给test的变量)。