2013-05-08 120 views
6

一些SciPy函數(如scipy.ndimage.interpolation.geometric_transform)可以將指針指向C函數作爲參數,以避免在輸入數組的每個點上調用Python可調用函數。在Cython中創建一個PyCObject指針

簡而言之:

  • 定義一個C模塊
  • 返回一個PyCObject&my_function指針和(任選地)一個void*指針在稱爲my_function某處函數以繞過
一些全局數據

相關API方法是PyCObject_FromVoidPtrAndDesc,您可以閱讀Extending ndimage in C以查看它的實際應用。

我對使用Cython保持我的代碼更易於管理非常感興趣,但我不確定我應該如何創建這樣的對象。任何,呃,指針?

+2

+1只是指針笑話:-p – Will 2013-05-08 14:16:55

+0

這似乎是正確的做! :D – 2013-05-08 14:50:50

回答

1

只要做到在用Cython你會用C做同樣的事情,直接調用PyCObject_FromVoidPtrAndDesc。以下是從您的鏈接移植到Cython的示例:

###### example.pyx ###### 

from libc.stdlib cimport malloc, free 
from cpython.cobject cimport PyCObject_FromVoidPtrAndDesc 

cdef int _shift_function(int *output_coordinates, double* input_coordinates, 
      int output_rank, int input_rank, double *shift_data): 
    cdef double shift = shift_data[0] 
    cdef int ii 
    for ii in range(input_rank): 
     input_coordinates[ii] = output_coordinates[ii] - shift 
    return 1 

cdef void _shift_destructor(void* cobject, void *shift_data): 
    free(shift_data) 

def shift_function(double shift): 
    """This is the function callable from python.""" 
    cdef double* shift_data = <double*>malloc(sizeof(shift)) 
    shift_data[0] = shift 
    return PyCObject_FromVoidPtrAndDesc(&_shift_function, 
             shift_data, 
             &_shift_destructor) 

性能應與純C版本相同。

請注意,Cyhton要求運營商&獲取函數地址。另外,Cython缺少指針取消引用運算符*,而是使用索引等價物(*ptr - >ptr[0])。

+0

感謝您的正確'cimport's!過了一段時間,我正在考慮從'.h'文件導入函數並做大致相同的操作,但我不確定如何處理引用和解除引用,因此您的示例將一次性清除它;) – 2013-05-09 21:20:14

0

我認爲這是一個壞主意。 Cython是爲了避免編寫PyObjects而創建的!此外,在這種情況下,通過用Cython編寫的代碼可能不會提高代碼的維護...... 無論如何,你可以在你用Cython代碼

from cpython.ref cimport PyObject 

導入的PyObject。

UPDATE

from cpython cimport * 

更安全。

乾杯, 達維德

+1

你可能注意到我寫了**'PyCObject' **而不是'PyObject'。 「PyObject」是一個普通的Python對象,而「PyCObject」是一個特殊的「PyObject」,用於保存指向原始內存地址的不透明指針。正如我所說,它被SciPy中的一些函數使用,他們只是從'PyCObject'中檢索函數指針並使用它,而沒有調用真正的Python方法的開銷。 ;) – 2013-05-08 19:03:00