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

How to structure a cython module with many identical function signatures

我写了一个 Cython 模块,它包装了一个外部 C 函数,并且它按预期工作。但是,我想包装由我的 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 及其附带的结构等已被 cimported ?

但是,当我将通用操作移到装饰器中时:

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)

我在

时遇到错误

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

幸运的是,您可以使用 C 函数指针执行非常相似的处理包装函数 a 的操作。您需要稍微不同的语法,但想法非常相似。 (为了这个答案,我假设您正在使用 中的 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)