2013-03-08 1 views
4

У меня есть некоторые данные из структуры, которая уже была выделена и инициализирована. Я могу гарантировать, что данные не будут освобождены во время жизни любого из этих объектов. Как обернуть это в объект Python в Cython? Далее делает не работу, но я надеюсь, что это объясняет мое намерение:Как написать тип расширения, который обертывает предварительно выделенные данные?

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

+0

A тип C. В частности, структура. Вы хотите точное определение структуры в C и Cython? –

+0

Я не думаю, что эти детали имеют значение. Но * как * это «не работает»? Можете ли вы предоставить пример [лучше] (http://sscce.org/)? – delnan

ответ

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: было бы хорошо, чтобы увидеть, если существует более простое решение

Смежные вопросы