初学者用 Python 扩展 C(特别是 Numpy)

Posted

技术标签:

【中文标题】初学者用 Python 扩展 C(特别是 Numpy)【英文标题】:Beginner extending C with Python (specifically Numpy) 【发布时间】:2010-02-18 16:02:09 【问题描述】:

我正在开发一个实时音频处理动态链接库,其中我有一个代表音频缓冲区的浮点数据的二维 C 数组。一个维度是时间(样本),另一个是渠道。我想将它作为 DSP 处理的 numpy 数组传递给 python 脚本,然后我想将它传递回 C,以便数据可以在 C 中继续处理链。C++ 中的成员函数执行处理如下:

void myEffect::process (float** inputs, float** outputs, int buffersize)

    //Some processing stuff

数组 inputsoutputs 大小相等。整数 buffersizeinputsoutputs 数组中的列数。在 python 方面,我希望由如下所示的函数执行处理:

class myPyEffect
    ...
    ...
    def process(self,inBuff):
    #inBuff and outBuff should be numpy arrays
        outBuff = inBuff * self.whatever # some DSP stuff
        return outBuff
    ...
    ...

现在,我的问题是,我怎样才能以最有效的方式将数据输入和输出 C(避免不必要的内存复制等)?到目前为止,对于简单的参数更改,我一直在使用如下 C-API 调用:

pValue = PyObject_CallMethod(pInstance, "setParameter", "(f)", value);

我对我的 numpy 数组使用类似的东西还是有更好的方法?感谢阅读。

【问题讨论】:

【参考方案1】:

您也许可以完全避免使用 NumPy C API。 Python 可以使用 ctypes 模块调用 C 代码,并且您可以使用数组的 ctypes 属性访问指向 numpy 数据的指针。

这是一个显示一维平方和函数过程的最小示例。

ctsquare.c

#include <stdlib.h>

float mysumsquares(float * array, size_t size) 
    float total = 0.0f;
    size_t idx;
    for (idx = 0; idx < size; ++idx) 
        total += array[idx]*array[idx];
    
    return total;

编译成ctsquare.so

这些命令行适用于 OS X,您的操作系统可能会有所不同。

$ gcc -O3 -fPIC -c ctsquare.c -o ctsquare.o
$ ld -dylib -o ctsquare.so -lc ctsquare.o

ctsquare.py

​​>
import numpy
import ctypes

# pointer to float type, for convenience
c_float_p = ctypes.POINTER(ctypes.c_float)

# load the library
ctsquarelib = ctypes.cdll.LoadLibrary("ctsquare.so")

# define the return type and arguments of the function
ctsquarelib.mysumsquares.restype = ctypes.c_float
ctsquarelib.mysumsquares.argtypes = [c_float_p, ctypes.c_size_t]

# python front-end function, takes care of the ctypes interface
def myssq(arr):
    # make sure that the array is contiguous and the right data type
    arr = numpy.ascontiguousarray(arr, dtype='float32')

    # grab a pointer to the array's data
    dataptr = arr.ctypes.data_as(c_float_p)

    # this assumes that the array is 1-dimensional. 2d is more complex.
    datasize = arr.ctypes.shape[0]

    # call the C function
    ret = ctsquarelib.mysumsquares(dataptr, datasize)

    return ret

if __name__ == '__main__':
    a = numpy.array([1,2,3,4])
    print 'sum of squares of [1,2,3,4] =', myssq(a)

【讨论】:

谢谢!这很酷,但是,我正在创建的动态链接库是另一个应用程序的插件,因此,必须从插件调用 python 代码。这意味着我需要从输入缓冲区中的任何内容创建一个 numpy 数组,在 python 中处理它,然后将其返回给插件 dll。我不能像上面的示例中那样只指定 numpy 数组内容 a = numpy.array([1,2,3,4]) Ctypes 看起来像是在 python 脚本中使用库函数的绝佳工具,但是我正在使用 python扩展 C,而不是 C 来扩展 python。这样可以吗?

以上是关于初学者用 Python 扩展 C(特别是 Numpy)的主要内容,如果未能解决你的问题,请参考以下文章

python都能做什么

利用Python的pip命令安装nump

visual c++是啥?

看图学NumPy:掌握n维数组基础知识点,看这一篇就够了

nump库的简单函数介绍

初学python,感受和C的不同