Cython:“无法转换Python对象”错误

我正在尝试从Python调用带有数组参数的C函数的测试项目:

void testFn(int arr[]);

void testFn(int arr[])

{

arr[0] = 1;

arr[1] = 2;

}

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)

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代码。

用Cython可以自动处理转换到intdoublefloat等等,甚至char *(它是一个空终止的c-字符串)和一些STL-

容器,而不是指针(char *作为一个例外)。

有两种最常见的情况:

  1. python数据的内部表示形式已经是一个c数组(array.array,numpy-arrays)。
  2. 内部表示形式不是连续数组(例如list

在python中,我们无法以某种方式获取指针,因此必须在cython中完成。将array.arrayor或numpy.array(或任何其他支持buffer-

protocol的python对象ctypes.Array,例如,参见此SO-question传递给cython函数的首选是内存视图:

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

以下重要

  1. int[:]是python对象(类型化的内存视图),因此可以将其传递给python函数(defcpdef)。
  2. &arr[0]用于获取内存视图的缓冲区的地址。其结果是类型int *
  3. 该函数的调用是“类型安全的”,您不能例如array.array('I', [0]*2)将其传递给它,因为它不是int-memory-view,而是unsigned int-memory-view。

list与Co.合作的还有更多工作:信息没有存储在普通的c数组中,因此我们需要先将其复制到连续内存中,将此temp变量传递给我们的c代码,然后将结果复制回列表中,即cython函数可能如下所示

import array

def myTest2(lst):

tmp=array.array('i', lst)

myTest(tmp)

lst.clear()

lst.extend(tmp)

现在,在重新加载caller模块后:

>>> lst=[0,0]

>>> caller.myTest2(lst)

[1, 2]

因此,可以将列表的内容传递给c函数,但是基本上您想使用它,array.array或者numpy.array如果需要使用c代码进行数据交换。

以上是 Cython:“无法转换Python对象”错误 的全部内容, 来源链接: utcz.com/qa/408708.html

回到顶部