Numpy reshape方法是否会复制数据?非连续内存场景规则是什么
numpy reshape方法创建拷贝的场景及判定规则
官方说明的含义
注意:要实现重塑(即reshape操作),原始数组的大小必须与重塑后数组的大小一致。reshape方法会尽可能返回原始数组的无拷贝视图(no-copy view),但如果原始数组的内存缓冲区是非连续(noncontiguous)的,就不总能做到这一点。
这段说明的核心逻辑是:reshape操作本质是修改数组的shape(维度)和strides(每个维度相邻元素的内存步长)属性,如果仅修改这两个属性就能得到符合要求的新数组,就会返回无拷贝的视图,和原数组共享内存;如果修改步长也无法匹配目标维度的存储顺序,就必须重新排列元素、创建新的内存缓冲区,也就是生成拷贝。
如果原数组本身内存是非连续的,可调整的步长范围会受到很大限制,因此很多时候无法仅通过修改属性完成reshape,只能创建拷贝。
reshape创建拷贝的实际示例
我们可以用转置生成非连续数组的场景来复现拷贝行为:
import numpy as np # 第一步:创建一个连续的2D数组,默认是C连续(行优先存储) arr = np.arange(6).reshape(2,3) print("原数组是否连续:", arr.flags.c_contiguous) # 输出 True # 第二步:转置得到非连续数组,转置仅修改步长,不修改内存存储顺序 arr_transpose = arr.T print("转置后数组是否连续:", arr_transpose.flags.c_contiguous) # 输出 False # 第三步:对非连续的转置数组做reshape,拉平为1D数组 arr_reshaped = arr_transpose.reshape(-1) # 验证是否为拷贝:修改reshape后的数组,查看原数组是否变化 arr_reshaped[0] = 999 print("修改reshape结果后的原数组:\n", arr) # 输出的原数组第一个元素还是0,没有变成999,说明reshape生成了拷贝,两者内存不共享 # 也可以直接用np.shares_memory验证: print("是否共享内存:", np.shares_memory(arr_transpose, arr_reshaped)) # 输出 False
判定规则
不会创建拷贝(返回视图)的场景
只要满足:目标shape对应的步长,可通过原数组的步长和存储顺序(C/ Fortran连续)直接推导得到,不需要调整元素的存储顺序,就会返回视图:
- 原数组是C连续,reshape时使用默认
order='C'参数,绝大多数情况都返回视图 - 原数组是Fortran连续,reshape时指定
order='F'参数,也大概率返回视图 - 可以通过
arr_reshape.base is arr_original或者np.shares_memory(arr_reshape, arr_original)直接验证是否为视图
会创建拷贝的场景
只要无法仅通过调整步长得到目标shape的数组,就会触发拷贝,常见场景包括:
- 原数组内存非连续,且目标shape的步长和原数组步长无法匹配(比如上面的转置后拉平的场景)
- 显式指定了和原数组存储顺序不匹配的order参数:比如原数组是C连续,reshape时指定
order='F',大概率会生成拷贝 - 原数组的元素存储存在对齐问题,无法满足新shape的内存对齐要求(比较少见)
内容的提问来源于stack exchange,提问作者peter.petrov
相关产品推荐
相关产品推荐

