2013-03-08 52 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:很高興看到是否存在更簡單的解決方案