我想转换一些ctypes代码来代替使用cython,但我很难挣扎。 基本上,ctypes代码:
到目前为止,我的ctypes代码看起来像这样:
rlib.h
#ifndef RLIB_H
#define RLIB_H
typedef struct _FFIArray {
void* data;
size_t len;
} _FFIArray;
typedef struct _Result_Tuple {
_FFIArray e;
_FFIArray n;
} _Result_Tuple;
_Result_Tuple convert_to_bng_threaded(_FFIArray x, _FFIArray y);
void drop_float_array(_FFIArray x, _FFIArray y)
#endif
mylib.pxd
cdef extern from "rlib.h":
struct _FFIArray:
void* data
size_t len
struct _Result_Tuple:
_FFIArray e
_FFIArray n
cdef _Result_Tuple convert_to_bng_threaded(_FFIArray x, _FFIArray y)
cdef void drop_float_array(_FFIArray x, _FFIArray y)
util_cython.pyx
import cython
from mylib cimport _FFIArray, convert_to_bng_threaded, drop_float_array
def call_convert_bng(_FFIArray x, _FFIArray y):
return convert_to_bng_threaded(x, y)
def call_drop_float_array(_FFIArray x, _FFIArray y):
return drop_float_array(x, y)
setup.py
from setuptools import setup, Extension, find_packages
from Cython.Build import cythonize
from Cython.Distutils import build_ext
ext = Extension('util_cython',
sources=['util_cython.pyx'],
libraries=['latlon_bng',],
library_dirs=['.',],
include_dirs=['.']
)
extensions = [ext,]
setup(
name = "util_cython",
ext_modules = cythonize(extensions),
cmdclass={'build_ext': build_ext},
)
我有一些关于如何继续的问题:
首先,编译步骤目前失败:
python setup.py build_ext --inplace
Compiling util_cython.pyx because it changed.
[1/1] Cythonizing util_cython.pyx
Error compiling Cython file:
------------------------------------------------------------
...
import cython
from mylib cimport _FFIArray, convert_to_bng_threaded, drop_float_array
def call_convert_bng(_FFIArray x, _FFIArray y):
return convert_to_bng_threaded(x, y)
^
------------------------------------------------------------
util_cython.pyx:5:34: Cannot convert '_Result_Tuple' to Python object
Traceback (most recent call last):
File "setup.py", line 17, in <module>
ext_modules = cythonize(extensions),
File "/Users/sth/dev/cythonize_test/venv/lib/python2.7/site-packages/Cython/Build/Dependencies.py", line 912, in cythonize
cythonize_one(*args)
File "/Users/sth/dev/cythonize_test/venv/lib/python2.7/site-packages/Cython/Build/Dependencies.py", line 1034, in cythonize_one
raise CompileError(None, pyx_file)
Cython.Compiler.Errors.CompileError: util_cython.pyx
为什么Cython无法转换_Result_tuple
?
其次,如何定义一个cython函数来接受列表(或数组;支持__iter__
的任何内容),并将其内容复制到_FFIArray
结构中,这样我就可以调用call_convert_bng
?
答案 0 :(得分:1)
以下是未经测试的,因为我没有库代码,因此必须对其工作方式进行一些猜测。但它应该让你知道如何去做。
我首先使用Python数组类型来存储输入/输出。 standard library array type或numpy数组。它们将数组连续存储在内存中(如C所示),因此只要将_FFIArray
data
属性指向此内存即可输入。
def convert_bng(double[::1] x, double[::1] y):
# I'm assuming that the data is double, not float, but it's easy changed
# here the [::1] promises it's continuous in memory
cdef _FFIArray x_ffi, y_ffi
# get a pointer to the data, and cast it to void*
x_ffi.data = <void*>&x[0]
x_ffi.len = x.shape[0] # possibly *sizeof(double) - depends on the C api
# repeat for y
y_ffi.data = <void*>&y[0]
y_ffi.len = y.shape[0]
cdef _Result_Tuple result = convert_to_bng_threaded(x_ffi, y_ffi)
# get data pointers for the two result arrays
cdef double* e_ptr = <double*>(result.e.data)
cdef double* n_ptr = <double*>(result.n.data)
# now view your output arrays using memoryviews
# you need to tell it the length (this is how many doubles the contain)
cdef double[::1] e = <double[:result.e.len:1]>e_ptr
cdef double[::1] n = <double[:result.n.len:1]>n_ptr
# create a numpy copy of the two arrays
import numpy as np
e_numpy = np.copy(e)
n_numpy = np.copy(n)
# you can now free your two returned arrays
# I assume this is done with drop_float_array
drop_float_array(result.e,result.n)
# return as tuple containing two arrays to python
return e_numpy, n_numpy