如何通过 FFI 传递 Numpy PyArray*
How to pass Numpy PyArray* via FFI
想法是能够从库中修改数组,就像从函数中修改 "output" 一样。
示例:
ffi.cdef("""
//Reads data from a file, and store in the numpy array
void read_image(PyArray* arr);
""")
C = ffi.dlopen('libimage.so')
image = np.array([], dtype=np.float32)
C.read_image(image)
assert image.ndim == 2
您不能通过 CFFI 传递 CPython 特定的 PyXxx
结构:您需要传递标准 C 数据。通常我会回答你需要使用标准 C 接口设计你的 cdef()'ed 函数,例如:
ffi.cdef("""
struct myimage_t {
int width, height;
float *data;
};
int read_image(struct myimage_t *output); // fill in '*output'
void free_image(struct myimage_t *img); // free output->data
""")
myimage = ffi.new("struct myimage_t *")
if lib.read_image(myimage) < 0:
raise IOError
...
lib.free_image(myimage)
然后您需要手动将 myimage
转换为 numpy 数组,在上面“...”代码的某处。
一个更好的选择是使用 Python 回调:根据规范和 returns 一个 C 标准 float *
指针制作 numpy 数组的回调。 numpy 数组本身保存在回调中的某处。您可以将其保存为 Python 全局,或者更干净地使用通过 C 传递的 "handle"。需要 API 版本,而不是 ABI。在 _example_build.py:
ffi.cdef("""
extern "Python" float *alloc_2d_numpy_array(void *handle, int w, int h);
void read_image(void *handle);
""")
ffi.set_source("_example_cffi", """
void read_image(void *handle)
{
// the C code that eventually invokes
float *p = alloc_2d_numpy_array(handle, w, h);
// and then fill the data at 'p'
}
""")
ffi.compile(verbose=True)
在文件 example.py 中:
from _example_cffi import ffi, lib
class Context:
pass
@ffi.def_extern()
def alloc_2d_numpy_array(handle, w, h):
context = ffi.from_handle(handle)
context.image = np.ndarray([w, h], dtype=np.float32)
return ffi.cast("float *", ffi.from_buffer(context.image))
context = Context()
lib.read_image(ffi.new_handle(context))
image = context.image
想法是能够从库中修改数组,就像从函数中修改 "output" 一样。 示例:
ffi.cdef("""
//Reads data from a file, and store in the numpy array
void read_image(PyArray* arr);
""")
C = ffi.dlopen('libimage.so')
image = np.array([], dtype=np.float32)
C.read_image(image)
assert image.ndim == 2
您不能通过 CFFI 传递 CPython 特定的 PyXxx
结构:您需要传递标准 C 数据。通常我会回答你需要使用标准 C 接口设计你的 cdef()'ed 函数,例如:
ffi.cdef("""
struct myimage_t {
int width, height;
float *data;
};
int read_image(struct myimage_t *output); // fill in '*output'
void free_image(struct myimage_t *img); // free output->data
""")
myimage = ffi.new("struct myimage_t *")
if lib.read_image(myimage) < 0:
raise IOError
...
lib.free_image(myimage)
然后您需要手动将 myimage
转换为 numpy 数组,在上面“...”代码的某处。
一个更好的选择是使用 Python 回调:根据规范和 returns 一个 C 标准 float *
指针制作 numpy 数组的回调。 numpy 数组本身保存在回调中的某处。您可以将其保存为 Python 全局,或者更干净地使用通过 C 传递的 "handle"。需要 API 版本,而不是 ABI。在 _example_build.py:
ffi.cdef("""
extern "Python" float *alloc_2d_numpy_array(void *handle, int w, int h);
void read_image(void *handle);
""")
ffi.set_source("_example_cffi", """
void read_image(void *handle)
{
// the C code that eventually invokes
float *p = alloc_2d_numpy_array(handle, w, h);
// and then fill the data at 'p'
}
""")
ffi.compile(verbose=True)
在文件 example.py 中:
from _example_cffi import ffi, lib
class Context:
pass
@ffi.def_extern()
def alloc_2d_numpy_array(handle, w, h):
context = ffi.from_handle(handle)
context.image = np.ndarray([w, h], dtype=np.float32)
return ffi.cast("float *", ffi.from_buffer(context.image))
context = Context()
lib.read_image(ffi.new_handle(context))
image = context.image