我正在尝试从Python调用带有数组参数的C函数的测试项目:
test.cpp :
void testFn(int arr[]); void testFn(int arr[]) { arr[0] = 1; arr[1] = 2; }
caller.pyx :
import ctypes cdef extern from "test.cpp": void testFn(int arr[]) def myTest(): a = [0, 0] arr = a.ctypes.data_as(ctypes.POINTER(ctypes.c_integer)) testFn(arr) print(arr)
setup.caller.py :
from distutils.core import setup from distutils.extension import Extension from Cython.Distutils import build_ext sourcefiles = ['caller.pyx'] ext_modules = [Extension("caller", sourcefiles)] setup( name = 'test app', cmdclass = {'build_ext': build_ext}, ext_modules = ext_modules )
但是,当我尝试构建项目时,出现错误:
$ python setup.caller.py build_ext --inplace running build_ext cythoning caller.pyx to caller.c Error compiling Cython file: ------------------------------------------------------------ ... def myTest(): a = [0, 0] arr = a.ctypes.data_as(ctypes.POINTER(ctypes.c_integer)) testFn(arr) ^ ------------------------------------------------------------ caller.pyx:13:11: Cannot convert Python object to 'int *'
这个问题经常出现,但是我找不到一个很好的重复目标,这超出了“只要这样做就行”的范围。
这是一种非常常见的情况:您尝试将一些python数据结构传递给需要指针的c代码int *, double *,...。但是,指针不是python对象,因此我们无法将它们从python代码传递到python代码。
int *, double *,...
用Cython可以自动处理转换到int,double,float等等,甚至char *(它是一个空终止的c-字符串)和一些STL- 容器,而不是指针(char *作为一个例外)。
int
double
float
char *
有两种最常见的情况:
array.array
list
1.通过内存视图传递:
在python中,我们无法以某种方式获取指针,因此必须在cython中完成。将array.arrayor或numpy.array(或任何其他支持buffer- protocol的python对象ctypes.Array,例如,参见此SO-question传递给cython函数的首选是内存视图:
numpy.array
ctypes.Array
def myTest(int[:] arr): testFn(&arr[0])
现在从python调用它:
>>> import array >>> a=array.array('i', [0]*2) >>> import caller >>> caller.myTest(a) >>> a array('i', [1, 2]) #it worked
以下重要
int[:]
def
cpdef
&arr[0]
int *
array.array('I', [0]*2)
unsigned int
2.传递非连续内存(例如列表):
list与Co.合作的还有更多工作:信息没有存储在普通的c数组中,因此我们需要先将其复制到连续内存中,将此temp变量传递给我们的c代码,然后将结果复制回列表中,即cython函数可能如下所示
import array def myTest2(lst): tmp=array.array('i', lst) myTest(tmp) lst.clear() lst.extend(tmp)
现在,在重新加载caller模块后:
caller
>>> lst=[0,0] >>> caller.myTest2(lst) [1, 2]
因此,可以将列表的内容传递给c函数,但是基本上您想使用它,array.array或者numpy.array如果需要使用c代码进行数据交换。