2013-03-08 51 views
4

我有一些已经分配和初始化的结构数据。 我可以保证在任何这些对象生命周期中数据都不会被释放。我如何将它封装在Cython中的Python对象中?下面确实的工作,但我希望它解释我的意图:如何编写包装预分配数据的扩展类型?

from libc.stdlib cimport malloc 

ctypedef struct Point: 
    int x 
    int y 

cdef class _MyWrapper: 
    cdef Point* foo 
    def __cinit__(self, Point* foo): 
     self.foo = foo 

def create_eternal_MyWrapper(int x, int y): 
    cdef Point* p 
    p = <Point*>malloc(sizeof(Point)) 
    p.x = x 
    p.y = y 
    return _MyWrapper(p) 

运行用Cython这个输出:

Error compiling Cython file: 
------------------------------------------------------------ 
... 
def create_eternal_MyWrapper(int x, int y): 
    cdef Point* p 
    p = <Point*>malloc(sizeof(Point)) 
    p.x = x 
    p.y = y 
    return _MyWrapper(p) 
        ^
------------------------------------------------------------ 

examplecy.pyx:17:23: Cannot convert 'Point *' to Python object 
+0

什么是MyAllocatedData?一个C结构? 'cdef类'?一种Python对象? – delnan 2013-03-08 18:56:05

+0

C类型。具体来说,一个结构。你想在C和Cython中确切的结构定义吗? – 2013-03-08 18:57:24

+0

我不认为这些细节很重要。但*如何*它“不起作用”?你能提供一个[更好](http://sscce.org/)的例子吗? – delnan 2013-03-08 19:14:14

回答

0

正如所讨论的here,既__init____cinit__方法使用PyObject_Call API函数,它只能接受PyObject类型的参数。所以,这也如同FAQ建议,你应该初始化C-属性全局的工厂方法内部:

from libc.stdlib cimport malloc 

ctypedef struct Point: 
    int x 
    int y 

cdef class _MyWrapper: 
    cdef Point* fooless 
    def __init__(self, *args, **kwargs): 
     raise TypeError("This class cannot be instantiated from Python") 

cpdef _MyWrapper create_MyWrapper(int x, int y): 
    cdef _MyWrapper w = _MyWrapper.__new__(_MyWrapper) 

    cdef Point* p 
    p = <Point*>malloc(sizeof(Point)) 
    p.x = x 
    p.y = y 

    w.foo = p 

    # initialize all other fields explicitly 
    # ... 

    return w 

一门课程可以在_MyWrapper本身创建一个专用的初始化方法,但我认为这将是相当不安全的,因为用户在类实例化后可以忘记调用这种方法。

PS:很高兴看到是否存在更简单的解决方案