【问题标题】:How to pass Numpy PyArray* via FFI如何通过 FFI 传递 Numpy PyArray*
【发布时间】:2017-01-07 11:39:12
【问题描述】:

想法是能够从库中修改数组,就像函数的“输出”一样。 示例:

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

【问题讨论】:

    标签: python numpy python-cffi


    【解决方案1】:

    您不能通过 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 回调:根据规范创建 numpy 数组并返回 C 标准 float * 指针的回调。 numpy 数组本身保存在回调中的某个位置。您可以将其保存为 Python 全局,或者更干净地使用通过 C 传递的“句柄”。需要 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
    

    【讨论】:

    • 有意思,谢谢你的回复。很遗憾我们不能这样做......我们无法访问 numpy 的数组 C API。在 Torch 中,我们可以使用 FFI 轻松直接访问他们的矩阵对象,这很有帮助。
    • 很遗憾,您的 x86 可执行文件在 ARM 智能手机上不再工作。如果您有使用 CPython C API 操作 PyObjects 的代码,那么是的,它不能与 cffi 一起使用;这是 cffi 设计目标的一部分。我的回答给出了如何使用 cffi 的方法实现相同结果的示例——当您需要访问某些 Python 对象时,使用 Python 编写的回调。
    猜你喜欢
    • 2021-11-07
    • 2014-02-19
    • 1970-01-01
    • 2021-10-31
    • 1970-01-01
    • 1970-01-01
    • 2021-10-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多