如何现代化改造使用已弃用NumPy C API的Python扩展代码
代码适配改造
你看到的这个警告不是说你代码里用了已经被弃用的API,只是NumPy头文件默认开启了旧版API兼容,提示你显式声明目标API版本,来关闭兼容层、消除警告。
你现有代码的核心API调用(PyArray_SimpleNew、PyArray_DATA等)本身就是NumPy 1.7之后保留的标准非弃用接口,只需要做少量调整就能完全符合现代API规范:
- 保留
NPY_NO_DEPRECATED_API宏定义,注意必须放在#include <numpy/arrayobject.h>之前,否则宏不会生效。如果需要适配更高版本的NumPy特性,可以把宏的取值改成对应版本,比如要适配NumPy 1.20+的API就写#define NPY_NO_DEPRECATED_API NPY_1_20_API_VERSION,指定后所有早于该版本的弃用接口都会在编译时直接报错,方便你排查旧接口调用。 - 去掉不必要的堆内存分配:维度数组
dims长度固定为2,直接在栈上分配即可,不需要手动new/delete,既减少开销也避免内存泄漏风险。 - 补充必要的错误检查:
PyArray_SimpleNew在内存不足等异常场景下会返回NULL并设置Python异常,加个判断能避免空指针崩溃。 - 索引变量用
npy_intp类型和NumPy内部的长度类型保持一致,避免跨平台时的类型不匹配问题。
改造后的完整代码如下:
#include <Python.h> #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION #include <numpy/arrayobject.h> PyObject* f() { npy_intp dims[2] = {3, 4}; PyObject* pyarray = PyArray_SimpleNew(2, dims, NPY_DOUBLE); if (!pyarray) { return NULL; } double* array_buffer = static_cast<double*>(PyArray_DATA(reinterpret_cast<PyArrayObject*>(pyarray))); for (npy_intp i = 0; i < dims[0]; ++i) { for (npy_intp j = 0; j < dims[1]; ++j) { // 保留原代码的列优先填充逻辑 array_buffer[j * dims[0] + i] = j + 100 + i; } } return pyarray; }
官方迁移参考查找方法
你可以直接在NumPy官方文档的C-API参考板块找对应内容:
- 首先搜索
NPY_NO_DEPRECATED_API关键字,对应的说明页会明确给出不同版本API的版本宏取值、每个版本标记弃用的接口列表,以及弃用接口对应的替代方案。 - 每个C API函数的单独说明页,都会标注该接口的首次引入版本、是否被弃用、弃用版本以及推荐替代接口,编译时如果遇到具体的弃用提示,直接搜对应函数名就能拿到迁移指引。
- 如果你是从NumPy 1.6及更早的老版本API迁移,文档里有专门的1.7版本API迁移指南,列了全量的新旧接口映射关系,可以直接对照修改。
注:如果需要使用NumPy 2.0之后的新API,只需要把宏的版本号改成
NPY_2_0_API_VERSION即可,上述代码里用到的接口在2.0版本中依然是标准非弃用接口,不需要额外修改。
内容的提问来源于stack exchange,提问作者Joachim W
相关产品推荐
相关产品推荐

