2014-05-08 220 views
4

我剛開始熟悉Cython,嘗試將C庫中的一些結構包裝到Python方法和類中。我不明白的是如何從(初始化的)C結構轉換爲相應的Python類。缺少什麼我在這裏: 將Cython結構中的C結構轉換爲Python類

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:

cdef struct test_struct: 
    pass 
ctypedef test_struct test 

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

我.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 

一個從C頭文件片段

一切都取決於返回s代理工作正常。我在ret等中得到了一個正確的值。但是在return語句中強制轉換似乎不正確或缺少更多信息。發行t = do_something(42) Python段錯誤。

的段錯誤本身是不是所有有幫助:

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魔法嗎?

+0

你不想投的結構。你想*創建一個'Test'實例,並用'struct'初始化它。我假設你已經嘗試過:'返回Test(t)'[或者你的初始化程序擁有的任何簽名]。 – Bakuriu

回答

5

您需要使Test成爲圍繞C類型的實際包裝。但是你也不能將C參數傳遞給Python函數(比如構造函數)。所以你也需要一個工廠功能。這裏有一個例子:

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) 
+0

我相信'def _setup'中的'def'應該是'cdef _setup' – Carpetfizz