包装/铸造C结构在用Cython到Python类 [英] Wrapping/Casting C struct in Cython to Python class

查看:117
本文介绍了包装/铸造C结构在用Cython到Python类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚开始让自己熟悉用Cython,试图从C库到Python方法和类包装的一些结构。我真的不明白的是如何从(初始化)C的结构为相应的Python类铸件应工作。缺少什么我在这里:

I'm just starting to get myself familiar with Cython, trying to wrap some structs from a C library to Python methods and classes. What I do not really understand is how casting from (initialized) C structs to the corresponding Python class should work. What am I missing here:

从C头文件中的代码片段:

A snippet from the C header file:

struct test_struct {
    int _something;
    complex_struct* _another;
};
typedef struct test_struct test;

test *test_new(void);
int some_method(test **n, int irrelevant);

从我.pxd相应的代码段:

Corresponding snippet from my .pxd:

cdef struct test_struct:
    pass
ctypedef test_struct test

test* test_new()
int some_method(test **n, int irrelevant)

我.pyx:

My .pyx:

def do_something(int irrelevant):
    cdef test* t = test_new()
    ret = some_method(&t, irrelevant)

    # Here comes the problem...
    return <Test?>t

cdef class Test:  
    cdef test* _t

    # cinit here and some methods here. No members except _t

之前的所有return语句工作正常。我得到了 RET 正确的值等,但在return语句中投似乎是不正确或丢失的更多信息。当发出 T = do_something(42)的Python段错误。

Everything up to the return statement works fine. I get a correct value in ret, etc. But the cast in the return statement seems to be incorrect or its missing more information. When issuing t = do_something(42) Python segfaults.

该段错误本身是不是在所有有用的:

The segfault itself is not at all helpful:

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7a9e74b in internal_print () from /usr/lib/libpython2.7.so.1.0
(gdb) bt
#0  0x00007ffff7a9e74b in internal_print () from /usr/lib/libpython2.7.so.1.0
#1  0x00007ffff7a81adb in PyFile_WriteObject () from /usr/lib/libpython2.7.so.1.0
#2  0x00007ffff7b19acb in sys_displayhook () from /usr/lib/libpython2.7.so.1.0
#3  0x00007ffff7a64c23 in PyObject_Call () from /usr/lib/libpython2.7.so.1.0
#4  0x00007ffff7af2ff7 in PyEval_CallObjectWithKeywords () from /usr/lib/libpython2.7.so.1.0
#5  0x00007ffff7af6f3b in PyEval_EvalFrameEx () from /usr/lib/libpython2.7.so.1.0
#6  0x00007ffff7af91b0 in PyEval_EvalCodeEx () from /usr/lib/libpython2.7.so.1.0
#7  0x00007ffff7af92b2 in PyEval_EvalCode () from /usr/lib/libpython2.7.so.1.0
#8  0x00007ffff7b11f9f in run_mod () from /usr/lib/libpython2.7.so.1.0
#9  0x00007ffff7b13ec0 in PyRun_InteractiveOneFlags () from /usr/lib/libpython2.7.so.1.0
#10 0x00007ffff7b140ae in PyRun_InteractiveLoopFlags () from /usr/lib/libpython2.7.so.1.0
#11 0x00007ffff7b1470e in PyRun_AnyFileExFlags () from /usr/lib/libpython2.7.so.1.0
#12 0x00007ffff7b24bcf in Py_Main () from /usr/lib/libpython2.7.so.1.0
#13 0x00007ffff746f000 in __libc_start_main () from /usr/lib/libc.so.6
#14 0x000000000040073e in _start ()

正如你所看到的, do_something 方法应该返回类型测试的Python对象。我需要什么补充,使施法成功?我是否需要手动映射结构的Python类?有一些神奇的用Cython我可以使用?

As you can see, the do_something method should return a Python object of type Test. What do I need to add to make the cast successful? Do I need to manually map the struct to the Python class? Is there some Cython magic I can use?

推荐答案

您需要让测试绕成的C类型的实际包装。但你也可以不通过一个C参数一个Python函数(如构造函数)。所以,你需要一个工厂函数为好。这里有一个例子:

You need to make Test into an actual wrapper around the C type. But you also cannot pass a C argument to a Python function (such as a constructor). So you'll need a factory function as well. Here's an example:

cdef class Test:
    cdef test* _t

    def __cinit__(self):
        self._t = NULL

    def _setup(self, test* t):
        self._t = t
        return self

    property something:
        def __get__(self):
            return self._t._something
        def __set__(self, int val):
            self._t._something = val

cdef Test_create(test* t):
    return Test()._setup(t)

然后在 do_something()

return Test_create(t)

这篇关于包装/铸造C结构在用Cython到Python类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆