numpy基础切片(如arr[2:5]、arr[:,1]、arr.t等)默认返回视图,修改会同步影响原数组;高级索引(如arr[[0,2]]、arr[arr>3])返回副本,修改不影響原数组;可通过sub.base is arr或实测修改验证。

因为 NumPy 切片默认返回 view,不是 copy——你改的不是“一份快照”,而是原数组内存本身。
哪些操作悄悄返回 view,改了就影响原数组?
基础切片语法几乎都返回 view,包括:
-
arr[2:5]、arr[:-1]、arr[::2] -
arr[:, 1]、arr[1:3, :](只要步长为整数且内存连续) -
arr.T、arr.reshape(3, 4)、arr.astype(np.float32)(部分类型转换也是view)
这些操作不分配新内存,只重解释 data.ptr 和 strides。一旦执行 sub[:] = x 或 sub.fill(x),原数组立刻同步变化。
为什么 arr[[0, 2]] 或 arr[arr > 3] 看似一样却“安全”?
它们触发的是高级索引(advanced indexing),NumPy 必须复制数据才能拼出非连续位置的元素,所以返回独立 copy:
-
arr[[0, 2]]→ 返回新数组,改它不影响arr -
arr[arr > 3]→ 同样返回copy,且无法用=反向赋值回原数组
但注意:arr[arr > 3] = 99 是特例:这是 NumPy 的原地布尔赋值语法,会直接修改原数组,和是否是 view 无关。
怎么快速判断 sub 是 view 还是 copy?
别猜,动手验证:
- 检查
sub.base is arr→True表示是view - 比较内存地址:
sub.data.ptr == arr.data.ptr→ 相同即共享内存 - 最直白:
sub[0] = -1后看arr[0]是否变
特别注意:arr.setflags(write=False) 会让所有基于它的 view 都变成只读,此时 sub[:] = x 会报 ValueError: assignment destination is read-only——不是切片错了,是原数组被锁了。
链式索引 B[i_b][j_b] 为什么总改不动原数组?
因为 B[i_b] 先执行,而 i_b 是整数数组 → 触发高级索引 → 返回 copy;后续的 [j_b] 是在这个临时副本上操作,原 B 完全没参与。
正确写法只有两种:
- 一步到位布尔/花式索引:
B[i_b[:, None], j_b](广播配合高级索引) - 用
np.ix_构造可索引网格:B[np.ix_(i_b, j_b)] = True
任何中间出现方括号嵌套两次以上的表达式,都要警惕它是不是悄悄创建了副本再丢弃。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











