如何构建具有许多相同功能签名的cython模块

时间:2016-05-20 11:02:51

标签: python cython

我编写了一个包装外部C函数的Cython模块,它正在按预期工作。但是,我想包装我的C二进制文件提供的其余函数,它们具有相同的签名。在Python中,我可以这样做:

def boilerplate(func):
    def wrapped_f(c, d):
        # modify x and y, producing mod_c and mod_d
        result = func(mod_c, mod_d)
        # modify foreign function return values, producing final_c, final_d
        return final_c, final_d
    return wrapped_f

@boilerplate
def func_a(a, b)
   return _foreign_func_a(a, b)

@boilerplate
def func_b(a, b)
   return _foreign_func_b(a, b)

我是否可以在Cython中使用类似的模式,以便“cythonise”wrapped_f,假设_foreign_func_a及其附带的结构等已被cimport编辑?

然而,当我将通用操作移动到装饰器中时:

def boilerplate(func):
    def wrapped(double[::1] wlon, double[::1] wlat):
        cdef _FFIArray x_ffi, y_ffi
        x_ffi.data = <void*>&wlon[0]
        x_ffi.len = wlon.shape[0]
        y_ffi.data = <void*>&wlat[0]
        y_ffi.len = wlat.shape[0]
        cdef _Result_Tuple result = func(x_ffi, y_ffi)
        cdef double* eastings_ptr = <double*>(result.e.data)
        cdef double* northings_ptr = <double*>(result.n.data)
        cdef double[::1] e = <double[:result.e.len:1]>eastings_ptr
        cdef double[::1] n = <double[:result.n.len:1]>northings_ptr

        e_numpy = np.copy(e)
        n_numpy = np.copy(n)
        drop_float_array(result.e, result.n)
        return e_numpy, n_numpy
    return wrapped

@boilerplate
def convert_bng(double[::1] lons, double[::1] lats):
    """wrapper around threaded conversion function

    """
    return convert_to_bng_threaded(lons, lats)

时出错
  • 尝试将x_ffiy_ffi转换为_FFIArray转换为wrapped
  • 中的Python对象
  • func
  • 中将Python对象_Result_Tuple转换为wrapped
  • lons中将lats_FFI_Array转换为convert_to_bng_threaded
  • _Result_Tuple转换回convert_bng_threaded
  • 中的Python对象

1 个答案:

答案 0 :(得分:1)

您的基本问题(基于您更新的问题)是您尝试包装一个采用纯C数据类型的函数(因此只能定义为cdef函数,并且可以从Cython但不是Python调用。但是,装饰器可以处理Python函数,所以它并没有完全结合在一起。

幸运的是,您可以使用C函数指针执行非常类似的处理包装函数的操作。你需要一个稍微不同的语法,但这个想法非常相似。 (为了这个答案,我假设您正在使用来自this previous question的C数据类型的定义,我认为这是合理的)

# pass a function pointer in
cdef boilerplate(_Result_Tuple (*func)(_FFIArray, _FFIArray)):
    def wrapped(double[::1] wlon, double[::1] wlat):
        cdef _FFIArray x_ffi, y_ffi
        x_ffi.data = <void*>&wlon[0]
        x_ffi.len = wlon.shape[0]
        y_ffi.data = <void*>&wlat[0]
        y_ffi.len = wlat.shape[0]
        cdef _Result_Tuple result = func(x_ffi, y_ffi)
        cdef double* eastings_ptr = <double*>(result.e.data)
        cdef double* northings_ptr = <double*>(result.n.data)
        cdef double[::1] e = <double[:result.e.len:1]>eastings_ptr
        cdef double[::1] n = <double[:result.n.len:1]>northings_ptr

        e_numpy = np.copy(e)
        n_numpy = np.copy(n)
        drop_float_array(result.e, result.n)
        return e_numpy, n_numpy
    return wrapped

# do this instead of using a decorator syntax
convert_bng = boilerplate(&convert_to_bng_threaded)