我有一些来自已分配和初始化的结构的数据。 我可以保证在任何这些对象的生命周期内都不会释放数据。我如何将它包装在 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
最佳答案
讨论 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:很高兴看到是否存在更简单的解决方案
关于python - 如何编写包装预分配数据的扩展类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15301216/