NumPy 只读数组 resize 后,新增区域未初始化甚至崩溃
NumPy 2.5.4 的原地扩容只在可写时初始化新增内存。保留只读原数组,以新容器明确初始化后复制有效前缀。
只读 ndarray 扩容后,新尾部出现不稳定数字,object 数组甚至在访问或释放时使进程退出。遇到这类症状,应立即停用对只读原对象的 resize(),不要为了观察结果继续读取可疑尾部。
NumPy 2.5.4 与 2.3.5 有相应记录。2.5.4 的原地 resize 路径可以重新分配存储,但只有数组可写时才初始化新增区域。只读数组绕过了这段初始化,新的字节可能不是正常的零值;object dtype 中的未初始化内容还涉及对象指针,不能当成普通缺失值填补。
需要更大容器时,新建并初始化
如果需求是保留一维数组前缀,并把新增部分补成零,可以明确创建另一个数组:
import numpy as np
source = np.array([10, 20, 30], dtype=np.int64)
source.flags.writeable = False
new_size = 5
if new_size < source.size:
raise ValueError("this operation only grows the array")
grown = np.zeros(new_size, dtype=source.dtype)
grown[:source.size] = source
source 仍保持只读且没有改变大小;后续需要新长度的代码改用 grown。旧视图继续看到旧数组,不能要求其他持有者的引用自动指向新对象。
示例针对一维普通数值数组,零是这里明确采用的填充值。object 数组若同样采用此方案,零值是 Python 数字零,复制已有项也只是复制对象引用,不会深复制内部列表或其他可变对象;业务需要 None 或独立对象时,应先按约定初始化,不要把它们混作同一种空值。
结构化 dtype、掩码数组和多维数据需要另外定义新增记录、有效区域与元素顺序。也不要改用 np.resize() 后就假定新增位置是零,它会按自身规则重复原数据。
只读性与引用检查不能互相替代
Python 3.14 的 resize 引用检查误判讨论的是合法所有权与引用判断。本题是只读数组扩容后的初始化缺口,关闭 refcheck 无法补上新增内存的初始化;强制恢复可写性又可能违反其他持有者的约定。
不要对已经经历可疑原地扩容的 object 数组继续做业务检查。保留既有日志,在隔离环境用正常原输入重新建立数据;进程已退出时,还应按任务状态确认外部写入完成到了哪一步,不能盲目重跑整批。
截至 2026 年 10 月 26 日,正式 2.5.4 仍有上述可写性条件。新建方案的验收应检查前缀、填充值、dtype、原对象未变,以及后续消费者确实接收了新数组。只在某次运行看到全零,不能证明原地扩容路径已经安全。


