如何编写包含预分配数据的扩展类型?

时间:2013-03-08 18:54:17

标签: python c cython

我从已经分配和初始化的结构中获得了一些数据。 我可以保证在这些对象的生命周期中不会释放数据。如何在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

1 个答案:

答案 0 :(得分: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:很高兴看到是否存在更简单的解决方案