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

标签 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

最佳答案

讨论 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/

相关文章:

c - 如果我在循环中创建线程,则前 2 个线程不会被执行

c++ - Cython 为 libcpp.list 赋值

python - 如何使用 Python 脚本为批处理文件提供输入?

c - 在没有 main() 的情况下执行共享库

Python列表列表的所有组合

c - 在 C 语言中,如何验证一个字符串变量是否等于一个不是变量的特定字符串? (不比较两个字符串)

python - 如何测试 Cython 属性是否为生成器?

python - cython : numpy array 中可能的优化

python - 如何在数据框的数组列中选择一个元素?

python - 静态方法和继承设计