既然python归根结底是C语言,那么C语言能否直接使用numpy?

如题。
关注者
27
被浏览
20,150
登录后你可以
不限量看优质回答私信答主深度交流精彩内容一键收藏

答案是:不可以直接在C语言中使用NumPy,要分情况的。

虽然Python的NumPy库使用C语言实现,但它仍然需要Python解释器来解释和执行Python代码。NumPy提供了Python的高级数据结构和一些用于操作这些数据结构的函数和方法,这些函数和方法都是在Python层次上实现的,

比如数组的创建、形状操作、元素操作等。具体来说,以下方法是在Python层面实现的:

  • numpy.array
  • numpy.zeros
  • numpy.ones
  • numpy.arange
  • ndarray.reshape
  • ndarray.flatten
  • ndarray.item
  • ndarray.itemset
  • numpy.concatenate

这些方法是在Python层次上实现的,因此它们的执行速度相对较慢,也无法在C语言中直接使用,不能满足大规模数据处理的需求

为了提高执行速度,NumPy还提供了许多基于C语言实现的函数和方法,例如:

  • numpy.add
  • numpy.subtract
  • numpy.multiply
  • numpy.divide

这些函数是通过C语言编写的,可以充分利用CPU的并行计算能力,因此在大规模数据处理时能够获得更高的执行效率。

如果您想在C语言中使用NumPy中的算法和数据结构,您可以考虑使用NumPy提供的C API。NumPy提供了一组C函数,这些函数可以与NumPy数组进行交互,这些函数包括:

  • NPY_NO_EXPORT PyObject *PyArray_SimpleNew(int nd, npy_intp *dims, int typenum);
  • NPY_NO_EXPORT void *PyArray_DATA(PyArrayObject *obj);
  • NPY_NO_EXPORT npy_intp *PyArray_SHAPE(PyArrayObject *obj);

使用这些函数,您可以将NumPy数组传递给C语言函数,并在C语言中访问和操作它们。但是,这需要一些C语言和NumPy的知识和经验,因此需要具备一定的技术水平和编程能力。

一个C调用numpy的C-API示例

#include <Python.h>
#include <numpy/arrayobject.h>

void c_function(PyArrayObject *arr) {
    // 获取数组的形状和元素类型
    int ndim = PyArray_NDIM(arr);
    npy_intp *shape = PyArray_SHAPE(arr);
    int dtype = PyArray_TYPE(arr);

    printf("NumPy array with shape (%ld, %ld) and type %d\n", 
      shape[0], shape[1], dtype);

    // 访问数组的元素
    npy_float64 *data = PyArray_DATA(arr);
    npy_intp i, j;
    for (i = 0; i < shape[0]; i++) {
        for (j = 0; j < shape[1]; j++) {
            npy_float64 val = data[i * shape[1] + j];
            printf("%f ", val);
        }
        printf("\n");
    }
}

int main() {
    // 初始化Python解释器
    Py_Initialize();
    import_array();

    // 创建NumPy数组
    npy_intp dims[] = {2, 3};
    PyArrayObject *arr = (PyArrayObject *)PyArray_SimpleNew(2, dims, NPY_FLOAT64);
    npy_float64 *data = PyArray_DATA(arr);
    data[0] = 1.0; data[1] = 2.0; data[2] = 3.0;
    data[3] = 4.0; data[4] = 5.0; data[5] = 6.0;

    // 调用C函数,并传递NumPy数组作为参数
    c_function(arr);

    // 释放数组内存并清理Python解释器
    Py_XDECREF(arr);
    Py_Finalize();

    return 0;
}

一个Cython调用numpy的C-API或Python-API示例

然而,实际上高效的做法,会使用Cython对numpy函数的调用会在纯Python会相多高效的多。

下面这个例子中,使用了Cython来声明一个接受NumPy数组作为参数的函数。在函数中,用Cython的类型声明来获取数组的形状、元素类型和元素值,并进行了一些简单的操作。需要注意的是,Cython使用NumPy的数组切片语法来访问数组的元素,而不是C API中使用指针算术运算的方式。

在main函数中,创建了一个与前面相同的2x3的NumPy数组,并将其作为参数传递给了我们声明的函数。需要注意的是,在使用Cython声明的函数时,不需要像C语言中一样手动初始化和清理Cython底层会调用Python对应的API会自动为我们处理这些问题。

# cython: language_level=3
import numpy as np
cimport numpy as np

def c_function(np.ndarray[np.float64_t, ndim=2] arr):
    # 获取数组的形状和元素类型
    cdef np.npy_intp_t ndim = arr.ndim
    cdef np.npy_intp_t[2] shape = arr.shape
    cdef int dtype = arr.dtype.num

    print(f"NumPy array with shape ({shape[0]}, {shape[1]}) and type {dtype}")

    # 访问数组的元素
    cdef np.float64_t *data = &arr[0, 0]
    cdef np.npy_intp_t i, j
    for i in range(shape[0]):
        for j in range(shape[1]):
            val = data[i * shape[1] + j]
            print(f"{val:.2f} ", end="")
        print("")

def main():
    # 创建NumPy数组
    arr = np.array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]], dtype=np.float64)

    # 调用C函数,并传递NumPy数组作为参数
    c_function(arr)

if __name__ == "__main__":
    main()

类似地pandas很多数学函数用到numpy实现的api有纯Py实现的,有原生的C函数接口。但对于巨量的数据集也是力不从心的,这种情况下就要对那些API进行Cython和C函数的二次重构了。答主专长对Python项目的二次开发,Cython性能优化、C扩展功能定制与开发,有技术问题可戳她咨询

编辑于 2023-03-25 23:19・IP 属地广东