如何构建具有许多相同函数签名的 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
及其附带的结构等已被 cimport
ed ?
但是,当我将通用操作移到装饰器中时:
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_ffi
和 y_ffi
转换为 _FFIArray
到 wrapped
中的 Python 个对象
- 将 Python 对象
func
转换为 wrapped
中的 _Result_Tuple
- 将
lons
和 lats
转换为 convert_to_bng_threaded
中的 _FFI_Array
,以及
- 将
_Result_Tuple
转换回 convert_bng_threaded
中的 Python 对象
你的根本问题(根据你更新的问题)是你试图包装一个采用纯 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)
我写了一个 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
及其附带的结构等已被 cimport
ed ?
但是,当我将通用操作移到装饰器中时:
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_ffi
和y_ffi
转换为_FFIArray
到wrapped
中的 Python 个对象
- 将 Python 对象
func
转换为wrapped
中的 - 将
lons
和lats
转换为convert_to_bng_threaded
中的_FFI_Array
,以及 - 将
_Result_Tuple
转换回convert_bng_threaded
中的 Python 对象
_Result_Tuple
你的根本问题(根据你更新的问题)是你试图包装一个采用纯 C 数据类型的函数(因此只能定义为 cdef
函数,并且可以是从 Cython 调用但不是 Python)。然而,装饰器作用于 Python 函数,所以它并没有完全融合在一起。
幸运的是,您可以使用 C 函数指针执行非常相似的处理包装函数 a 的操作。您需要稍微不同的语法,但想法非常相似。 (为了这个答案,我假设您正在使用
# 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)