Cython:"无法转换Python对象"错误

时间:2017-10-29 21:24:33

标签: python cython

我试图让一个测试项目工作,用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 *'

1 个答案:

答案 0 :(得分:4)

这个问题经常出现,但是我无法找到一个好的重复目标,这将超越"只需这样做就可以了。#/ p>

这是一种非常常见的情况:您尝试将一些python数据结构传递给需要指针int *, double *,...的c代码。但是指针不是python对象,所以我们不能将它们从/传递给python代码。

有两种最常见的情况:

  1. python-data的内部表示已经是一个c-array(array.array,numpy-arrays)。
  2. 内部表示不是连续数组(例如list
  3. <强> 1。通过记忆视图传递:

    在python中我们无法以某种方式获取指针,因此必须在cython中完成。我将array.arraynumpy.array传递给cython函数的第一选择是内存视图(因为array.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
    

    以下是重要的

    1. int[:]是一个python对象(一个类型化的内存视图),因此可以传递给python函数(defcpdef)。
    2. &arr[0]用于获取内存视图缓冲区的地址。其结果是int *类型。
    3. 该函数的调用是&#34;类型安全&#34;,您不能将array.array('I', [0]*2)传递给它,因为它不是int - 内存视图而是{{ {1}} - 存储器视
    4. <强> 2。传递非连续记忆(例如列表):

      unsigned int和Co有更多的工作:信息不存储在普通的c-arrays中,所以我们需要先将它们复制到连续的内存中,将这个temp变量传递给我们的c-code并复制结果回到列表,我们的cython函数可能如下所示

      list

      现在重新加载import array def myTest2(lst): tmp=array.array('i', lst) myTest(tmp) lst.clear() lst.extend(tmp) 模块后:

      caller

      因此,可以将列表的内容传递给c函数,但如果您需要使用c代码进行数据交换,基本上您希望使用>>> lst=[0,0] >>> caller.myTest2(lst) [1, 2] array.array