代码之家  ›  专栏  ›  技术社区  ›  ead

Cython中的错误消息“无法将'double*'转换为Python对象”

  •  1
  • ead  · 技术社区  · 6 年前

    当我对以下Cython模块进行Cython化时

    %%cython
    cdef double *ptr=[1,2,3]
    print(ptr)
    

    我收到以下错误消息:

    但是,以下Cython模块:

    %%cython
    cdef double val=0.0
    print(val)
    

    是没有问题的cythonized。

    对于任何其他指针类型(即。 int * float * 等等)。

    1 回复  |  直到 5 年前
        1
  •  8
  •   ead    5 年前

    print 是一个纯Python函数,为了能够调用它,参数必须是Python对象。

    ptr 在第一个Cython模块中,nor val 第二种是python对象。但是有一个区别:a cdef double 可以通过Cython自动转换为Python浮点 PyFloat_FromDouble -这正是幕后发生的事情:Cython从 瓦尔 打印 然后把它毁掉。

    还有其他类型可以自动转换为Python对象: , float int &相似,但也 std::vector and other c++-containers .

    char * , Py_UNICODE* 它们的不同转世是一个例外(见后面的示例),因为这首先是不可能的,因为Cython不知道指针指向的数组(到底是数组吗?)的长度。

    这种情况下唯一的解决方案是:必须手动将内存内容转换为python列表(或它对应的任何python类型),这里以函数为例 convert_to_python :

    %%cython 
    cdef convert_to_python(double *ptr, int n):
        cdef int i
        lst=[]
        for i in range(n):
            lst.append(ptr[i])
        return lst
    
    cdef double *ptr=[1,2,3]
    print(convert_to_python(ptr,3))
    

    最值得注意的是, 获取作为参数的元素数-缺少信息Cython。

    顺便说一句:Cython会自动将已知长度的C数组转换为Python对象,例如:

    %%cython 
    cdef double arr[3] # length (=3) known to Cython 
    arr[:]=[1,2,3]
    print(arr)
    


    煤焦* signed char * , unsigned char * Py_UNICODE * 以及他们的 const -变体是“特殊的”,因为它们可以 be automatically converted 要么 bytes 煤焦* unicode -反对( Py_UNICODE* ),假设它是以null结尾的C字符串(即字符 \0 标志着结束)。因此,可以编写类似于

    cdef char a[3] 
    a = [90,0,90]   # ord('Z') = 90
    print(a)        # char[3] decays to char *
    # b"Z"
    

    可以看到,结果不是b“Z\x00Z”,因为字符串在第一个“\0”处会被自动截断。要确保转换为bytes对象的整个字符串必须指定长度:

    print(a[:3]) 
    # b"Z\x00Z"
    

    但是,如果没有,问题可能会出现 \0 在char数组中,这可能导致segfaults(读取超出范围)。