为何numpy记录的memoryview显示只读,但实际可修改?
为何Python会提示记录的memoryview是只读的?
>>> x = np.zeros(1, dtype='d,d,i') >>> x array([(0., 0., 0)], dtype=[('f0', '<f8'), ('f1', '<f8'), ('f2', '<i4')]) >>> memoryview(x).readonly False >>> memoryview(x[0]).readonly True
显然,x[0]并非只读,因为:
>>> x[0][0] += 1 >>> x[0] (1., 0., 0)
普通数组的memoryview不存在此问题:
>>> y = np.zeros((3, 4)) >>> memoryview(y).readonly False >>> memoryview(y[0]).readonly False
同样,已弃用的__array_interface__也能识别x[0]是可读写的:
>>> x.__array_interface__['data'] # 返回元组(地址,只读标记) (105553143159680, False) >>> x[0].__array_interface__['data'] (105553143159680, False)
我的实际问题出在C代码中,不过该问题也可通过纯Python代码复现。
我尝试在C代码中读写numpy记录,仅需获取数据地址。通过__array_interface__及其对应的C端__array_struct__可正常获取地址,但文档指出这是遗留方案,新代码应使用buffer protocol。
然而,buffer protocol(Python中由memoryview模拟)却认为记录是只读的,我必须显式请求只读缓冲区。虽然可从“只读”缓冲区获取地址并强行写入,但这种做法并不规范。
针对@tdelaney的评论更新:
我做了一个实验,编写了一个小型C函数,请求只读内存缓冲区,找到起始地址后强行递增其中的double值:
void foo(PyObject *object) { Py_buffer view; PyObject_GetBuffer(object, &view, PyBUF_CONTIG_RO); if (view.obj) { double *data = (double *)view.buf; *data += 1; } PyBuffer_Release(&view); }
随后在Python中查看数组结果:
对于记录数组,foo(x)和foo(x[1])均可正确递增数组元素。
对于二维double数组,foo(y)和foo(y[1])也可正确递增数组元素,而foo(y[1][2])无操作,符合预期。
因此,对于记录来说,np.void并未被复制,至少在此场景下是如此。
内容的提问来源于stack exchange,提问作者Frank Yellin
相关产品推荐
相关产品推荐

