You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 11:35:27