我编写了一个包装外部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_ffi
和y_ffi
转换为_FFIArray
转换为wrapped
func
_Result_Tuple
转换为wrapped
lons
中将lats
和_FFI_Array
转换为convert_to_bng_threaded
,_Result_Tuple
转换回convert_bng_threaded
答案 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)