Cython Numpy关于使用MemoryView时的NPY_NO_DEPRECATED_API警告
我正在把一个Cython的内存视图转换成一个numpy数组(这样就可以在纯Python代码中使用它):
from libc.stdlib cimport realloc
cimport numpy as np
DTYPE = np.float64
ctypedef np.float64_t DTYPE_t
cpdef np.ndarray[DTYPE_t] compute(DTYPE_t[:,::1] data):
cdef unsigned int Nchannels = data.shape[0]
cdef unsigned int Ndata = data.shape[1]
cdef DTYPE_t* output = NULL
cdef DTYPE_t[::1] mv
output = <DTYPE_t*>realloc(output, Ndata*sizeof(output))
if not output:
raise MemoryError()
mv = <DTYPE_t[:Ndata]>output
mv[10:Ndata-10] = 0.0
# various calculations...
return np.asarray(mv, dtype=DTYPE, order='C')
这个过程可以编译,但编译器给出了以下警告:
/Users/vlad/anaconda/lib/python2.7/site-packages/numpy/core/include
/nump/npy_1_7_deprecated_api.h:15:2: warning:
"Using deprecated NumPy API, disable it by #defining NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION" [-W#warnings]
我在setup.py文件中添加了建议的指令:
from distutils.core import setup, Extension
from Cython.Build import cythonize
import numpy
filename = 'agents3.pyx'
agents_module = Extension(
'Agents',
sources = [filename],
define_macros = [('NPY_NO_DEPRECATED_API', 'NPY_1_7_API_VERSION')],
include_dirs = [numpy.get_include()],
)
setup (name = 'Agents',
ext_modules = cythonize(agents_module)
)
但是现在它无法编译了,提示信息是:
Vlads-MacBook-Pro:program vlad$ python setup.py build_ext --inplace
Compiling agents3.pyx because it changed.
Cythonizing agents3.pyx
running build_ext
building 'Agents' extension
gcc -fno-strict-aliasing -I/Users/vlad/anaconda/include -arch x86_64 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -DNPY_NO_DEPRECATED_API=NPY_1_7_API_VERSION -I/Users/vlad/anaconda/lib/python2.7/site-packages/numpy/core/include -I/Users/vlad/anaconda/include/python2.7 -c agents3.c -o build/temp.macosx-10.5-x86_64-2.7/agents3.o
agents3.c:2273:52: error: use of undeclared identifier 'NPY_C_CONTIGUOUS'
__pyx_t_2 = ((!(PyArray_CHKFLAGS(__pyx_v_self, NPY_C_CONTIGUOUS) != 0)) != 0);
^
agents3.c:2311:52: error: use of undeclared identifier 'NPY_F_CONTIGUOUS'
__pyx_t_1 = ((!(PyArray_CHKFLAGS(__pyx_v_self, NPY_F_CONTIGUOUS) != 0)) != 0);
^
agents3.c:2474:42: error: no member named 'descr' in 'struct tagPyArrayObject'
__pyx_t_4 = ((PyObject *)__pyx_v_self->descr);
~~~~~~~~~~~~ ^
agents3.c:4026:27: error: no member named 'base' in 'struct tagPyArrayObject'
Py_XDECREF(__pyx_v_arr->base);
~~~~~~~~~~~ ^
/Users/vlad/anaconda/include/python2.7/object.h:823:34: note: expanded from macro 'Py_XDECREF'
#define Py_XDECREF(op) do { if ((op) == NULL) ; else Py_DECREF(op); } while (0)
^
agents3.c:4026:27: error: no member named 'base' in 'struct tagPyArrayObject'
Py_XDECREF(__pyx_v_arr->base);
~~~~~~~~~~~ ^
/Users/vlad/anaconda/include/python2.7/object.h:823:64: note: expanded from macro 'Py_XDECREF'
#define Py_XDECREF(op) do { if ((op) == NULL) ; else Py_DECREF(op); } while (0)
^
/Users/vlad/anaconda/include/python2.7/object.h:772:24: note: expanded from macro 'Py_DECREF'
--((PyObject*)(op))->ob_refcnt != 0) \
^
agents3.c:4026:27: error: no member named 'base' in 'struct tagPyArrayObject'
Py_XDECREF(__pyx_v_arr->base);
~~~~~~~~~~~ ^
/Users/vlad/anaconda/include/python2.7/object.h:823:64: note: expanded from macro 'Py_XDECREF'
#define Py_XDECREF(op) do { if ((op) == NULL) ; else Py_DECREF(op); } while (0)
^
/Users/vlad/anaconda/include/python2.7/object.h:775:34: note: expanded from macro 'Py_DECREF'
_Py_Dealloc((PyObject *)(op)); \
^
/Users/vlad/anaconda/include/python2.7/object.h:762:15: note: expanded from macro '_Py_Dealloc'
(*Py_TYPE(op)->tp_dealloc)((PyObject *)(op)))
^
/Users/vlad/anaconda/include/python2.7/object.h:115:47: note: expanded from macro 'Py_TYPE'
#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
^
agents3.c:4026:27: error: no member named 'base' in 'struct tagPyArrayObject'
Py_XDECREF(__pyx_v_arr->base);
~~~~~~~~~~~ ^
/Users/vlad/anaconda/include/python2.7/object.h:823:64: note: expanded from macro 'Py_XDECREF'
#define Py_XDECREF(op) do { if ((op) == NULL) ; else Py_DECREF(op); } while (0)
^
/Users/vlad/anaconda/include/python2.7/object.h:775:34: note: expanded from macro 'Py_DECREF'
_Py_Dealloc((PyObject *)(op)); \
^
/Users/vlad/anaconda/include/python2.7/object.h:762:45: note: expanded from macro '_Py_Dealloc'
(*Py_TYPE(op)->tp_dealloc)((PyObject *)(op)))
^
agents3.c:4035:16: error: no member named 'base' in 'struct tagPyArrayObject'
__pyx_v_arr->base = __pyx_v_baseptr;
~~~~~~~~~~~ ^
agents3.c:4070:30: error: no member named 'base' in 'struct tagPyArrayObject'
__pyx_t_1 = ((__pyx_v_arr->base == NULL) != 0);
~~~~~~~~~~~ ^
agents3.c:4093:44: error: no member named 'base' in 'struct tagPyArrayObject'
__Pyx_INCREF(((PyObject *)__pyx_v_arr->base));
~~~~~~~~~~~ ^
agents3.c:1065:37: note: expanded from macro '__Pyx_INCREF'
#define __Pyx_INCREF(r) Py_INCREF(r)
^
/Users/vlad/anaconda/include/python2.7/object.h:767:18: note: expanded from macro 'Py_INCREF'
((PyObject*)(op))->ob_refcnt++)
^
agents3.c:4094:41: error: no member named 'base' in 'struct tagPyArrayObject'
__pyx_r = ((PyObject *)__pyx_v_arr->base);
~~~~~~~~~~~ ^
11 errors generated.
error: command 'gcc' failed with exit status 1
Vlads-MacBook-Pro:program vlad$
我该怎么办呢?把这个过时的API调用留着可以吗?它试图访问base
字段——但我并没有这样做,这是Cython的问题。我只是简单地把一个内存视图转换成了一个numpy数组。有没有其他更简单、更安全的方法来做到这一点呢?
4 个回答
如果你想要隐藏那些过时警告,可以在使用clang编译时加上这个选项:extra_compile_args=['-Wno-#warnings']
。
而如果你用的是gcc,可以用这个选项:extra_compile_args=['-Wno-cpp']
,效果是一样的。
不过要注意,这样做也会把其他一些预处理指令的警告都隐藏起来。
我也遇到过同样的警告,我觉得这很正常。
如果你不想看到这个警告,在使用numpy的C接口时,你需要在C脚本前面加一行代码,但这行代码只是告诉编译器忽略“过时”的消息——无论有没有这行代码,效果似乎都是一样的。
我猜Cython编译器在生成C代码时没有加这行代码,我觉得这并不重要。
在Cython 3.0中,你可以通过在构建时定义C宏
NPY_NO_DEPRECATED_API
为NPY_1_7_API_VERSION
来消除这个警告:# distutils: define_macros=NPY_NO_DEPRECATED_API=NPY_1_7_API_VERSION
...
在旧版本的Cython中,设置这个宏会导致C编译失败,因为旧版Cython生成的代码使用了这个已经不推荐使用的C接口。不过,即使在最近的NumPy版本(包括1.18.x)中,这个警告也没有负面影响。你可以忽略这个警告,直到你(或者你的库的用户)切换到一个更新的NumPy版本,这个版本去掉了这个已经不推荐使用的接口,届时你也需要使用Cython 3.0或更高版本。因此,越早切换到Cython 3.0,对你的用户越好。
截至2023年2月,Cython 3.0还没有发布,所以建议升级到Cython 3.0以消除警告的建议并不太适用。
你可以忽略它的建议也不是最佳做法,因为这会导致开发者对警告感到疲惫、冷漠和无视,从而引发错误。
在早期的Cython版本中,可以通过定义C预处理宏 NPY_NO_DEPRECATED_API=1
来禁用这个警告,例如:
# distutils: define_macros=NPY_NO_DEPRECATED_API=1
我在使用cython-0.29.32和numpy-1.23.4时采用了这个方法,使用的功能子集没有问题。
为了进一步说明,Cython的在线文档提到,这是因为Cython使用了一个已经不再推荐使用的Numpy接口,目前这只是一个警告,我们可以选择忽略它。