2017-08-30 68 views
1

问题:用Cython:无法转换指向Python对象模块拆分后

Error compiling Cython file: 
------------------------------------------------------------ 
... 
cpdef Py_GetRemoteDevice(PyChannel Chan): 
    ret_val = mod_one.PyRemoteDevice() 
    cdef core.RemoteDevice * tmp 
    with nogil: 
     tmp = core.GetRemoteDevice(Chan.__instance) 
    ret_val.__set_ptr(tmp) 
         ^
------------------------------------------------------------ 

core/mod_two.pyx:11589:25: Cannot convert 'RemoteDevice *' to Python object 

背景: 我有一个相当大的C库,我用用Cython包装。起初,我在 中有两个文件core.pyx和core.pxd。然而,被包装的库的更多 生成的core.c文件越大。 250万行和计数。编译时间和内存使用量变得很麻烦。

我决定把东西分成多个.pyx文件。那时使用 的东西停止工作。

声明: 请记住,我已经大大简化了这个问题的东西。 包装的库有点大和专有。

的详细信息:
core.pxd - 包含C库
我包裹所有必要的组件。也是一个简单的Void *包装类声明。

cdef class Void: 
    cdef void *__void 
    cdef __set_ptr(self, void *ptr) 

cdef extern from "core.h": 
    ctypedef unsigned char U8 
    ctypedef unsigned int U32 

    void OS_MemSet(U8 *dest, U8 byte, U32 len) nogil 

cdef extern from "mod_one.h": 
    cdef struct _RemoteDevice 
    ctypedef _RemoteDevice RemoteDevice 

cdef extern from "mod_two.h": 
    cdef struct _Channel 
    ctypedef _Channel Channel 

core.pyx - 不是这里需要一大堆,实际上它只是 实施虚空*包装的。

cdef class Void: 
    cdef __set_ptr(self, void *ptr): 
     self.__void = ptr 

mod_one.pxd - 声明了包装类的远端设备C结构

cimport core 

cdef class PyRemoteDevice: 
    cdef core.RemoteDevice *__instance 
    cdef __set_ptr(self, core.RemoteDevice *ptr) 

mod_one.pyx - 定义远端设备包装类。注意 __set_ptr功能,这是cdef'd,并采取了远端设备*

from cpython.mem cimport PyMem_Malloc, PyMem_Free 
import core 
cimport core 

cdef class PyRemoteDevice: 
    def __cinit__(self): 
     self.__instance = <core.RemoteDevice *>PyMem_Malloc(sizeof(core.RemoteDevice)) 

    def __init__(self): 
     core.OS_MemSet(<core.U8 *>self.__instance, <core.U8>0, sizeof(core.RemoteDevice)) 

    cdef __set_ptr(self, core.RemoteDevice *ptr): 
     self.__instance = ptr 

    def __dealloc__(self): 
     if self.__instance is not NULL: 
      PyMem_Free(self.__instance) 
      self.__instance = NULL 

mod_two.pxd - 声明频道包装类,这是我,因为它是在函数中使用我只在这里展示 那正在造成我的问题。

cimport core 
cimport mod_one 

cdef class PyChannel: 
    cdef core.Channel *__instance 
    cdef __set_ptr(self, core.Channel *ptr) 

mod_two.pyx - 定义频道包装类并声明 Py_GetRemoteDevice函数,它从C库包装了GetRemoteDevice函数 。

from cpython.mem cimport PyMem_Malloc, PyMem_Free import core cimport core import mod_one cimport mod_one 

cdef class PyChannel: 
    def __cinit__(self): 
     self.__instance = <core.Channel *>PyMem_Malloc(sizeof(core.Channel)) 

    def __init__(self): 
     core.OS_MemSet(<core.U8 *>self.__instance, <core.U8>0, sizeof(core.Channel)) 

    cdef __set_ptr(self, core.Channel *ptr): 
     self.__instance = ptr 

    def __dealloc__(self): 
     if self.__instance is not NULL: 
      PyMem_Free(self.__instance) 
      self.__instance = NULL 

cpdef Py_GetRemoteDevice(PyChannel Chan): 
    ret_val = mod_one.PyRemoteDevice() 
    cdef core.RemoteDevice * tmp 
    with nogil: 
     tmp = core.GetRemoteDevice(Chan.__instance) 
    ret_val.__set_ptr(tmp) 
    return ret_val 

我得到的问题是,Cythonizing mod_two的时候,我得到了 以下错误:

Error compiling Cython file: 
------------------------------------------------------------ 
... 
cpdef Py_GetRemoteDevice(PyChannel Chan): 
    ret_val = mod_one.PyRemoteDevice() 
    cdef core.RemoteDevice * tmp 
    with nogil: 
     tmp = core.GetRemoteDevice(Chan.__instance) 
    ret_val.__set_ptr(tmp) 
         ^
------------------------------------------------------------ 

core/mod_two.pyx:11589:25: Cannot convert 'RemoteDevice *' to Python object 

我有点困惑,因为这个用来工作,当我有一切一个 模块。我可以看到的一个区别是,我的所有包装类在core.pyx中完全定义为 ,因为我不需要在模块之间共享它们。现在 我需要分享它们,所以我将它们分成.pyx和.pxd文件。

任何人都可以指向正确的方向吗?我搜索了Cython文档和Google ,但到目前为止,我还没有找到任何答案来解决我的问题。

谢谢,请让我知道是否需要任何额外的信息!

+0

看起来像你需要'ret_val'上的类型注释吗? – chrisb

+0

@chrisb,我想知道那件事,但是我一直无法使它工作。可能是因为我不确定它应该是什么样子。我试过 mod_one.PyRemoteDevice ret_val = mod_one.PyRemoteDevice() 没有运气。我会再试一次,只是为了确保。 – rahvin74

+0

好吧@micrisb,你是对的。只要我输入我最后的评论,我意识到我的错误。我需要'cdef'在我最后发布的内容前面,所以它会是'cdef mod_one.PyRemoteDevice ret_val = mod_one.PyRemoteDevice()'。我感觉有点傻!如果您将您的评论置于答案中,我会接受它。 – rahvin74

回答

0

访问扩展类型的c级函数需要cython知道确切的类型,否则它被视为一个通用的Python对象。所以需要这样的类型注释

cdef mod_one.PyRemoteDevice ret_val = ... 
+0

谢谢@chrisb,你是一位绅士和学者! – rahvin74