在Cython中创建PyCObject指针

6
一些SciPy函数(例如scipy.ndimage.interpolation.geometric_transform)可以将指向C函数的指针作为参数,以避免在输入数组的每个点上调用Python可调用函数。
简而言之:
  • 在C模块中定义一个名为my_function的函数
  • 返回一个带有&my_function指针和(可选的)void*指针的PyCObject,以传递一些全局数据
相关的API方法是PyCObject_FromVoidPtrAndDesc,您可以阅读Extending ndimage in C以了解其工作原理。
我非常有兴趣使用Cython来使我的代码更加可管理,但我不确定应该如何创建这样的对象。有任何建议吗?

2
+1 只是为了指针笑话 :-p - Will
这似乎是正确的事情要做!:D - F.X.
2个回答

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版本相同。

请注意,Cython需要运算符&来获取函数地址。此外,Cython缺少指针解引用运算符*,因此使用索引等效替代(*ptr -> ptr[0])。


感谢正确的 cimport!一段时间后,我考虑从 .h 文件中导入函数并进行大致相同的操作,但我不确定如何处理引用和解引用,所以您的示例一下子就澄清了这一切 ;) - F.X.

0

我认为这是一个不好的想法。Cython 的创建就是为了避免编写 PyObjects!此外,在这种情况下,通过 Cython 编写代码可能并不能提高代码维护性......

无论如何,您可以使用以下方式导入 PyObject:

from cpython.ref cimport PyObject

在你的Cython代码中。

更新

from cpython cimport *

更安全。

祝好, Davide


1
你可能会注意到我写的是 PyCObject 而不是 PyObjectPyObject 是普通的 Python 对象,而 PyCObject 是一个特殊的 PyObject,用于保存指向原始内存地址的不透明指针。正如我所说,它被 SciPy 中的一些函数使用,这些函数只需从 PyCObject 中检索函数指针并使用它,而无需调用真正的 Python 方法的开销。 ;) - F.X.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接