NumPy数组索引赋值疑问:两种索引方式为何结果不同?
NumPy数组索引赋值的差异解析
先看你的代码执行结果:
import numpy as np i = np.arange(2,4) a = np.arange(5) a[:][i] = 0 # 输出 [0 1 0 0 4] print(a) b = np.arange(5) b[i][:] = 0 # 输出 [0 1 2 3 4] print(b)
核心原因:切片索引 vs 数组索引的返回类型差异
NumPy里两种索引方式的返回结果本质不同:
- 切片索引(
arr[:]):返回原数组的视图(View),视图和原数组共享同一块内存空间,修改视图的元素会直接同步到原数组。 - 数组索引(
arr[i],i是整数数组):返回原数组的副本(Copy),副本是独立的内存块,修改副本不会影响原数组。
逐行拆解两个赋值操作
1. a[:][i] = 0的执行流程
- 第一步
a[:]:生成原数组a的视图,和a共享内存。 - 第二步
[i]:对这个视图进行数组索引,赋值操作会直接作用于视图对应的原数组内存位置,最终修改了原数组a。
2. b[i][:] = 0的执行流程
- 第一步
b[i]:对原数组b进行数组索引,返回的是b对应元素的独立副本,和原数组内存不共享。 - 第二步
[:]:对这个副本做切片赋值,修改的只是副本元素,原数组b的内存完全没被改动,所以输出还是初始值。
直观证明方法
用np.shares_memory()函数可以直接验证内存是否共享:
import numpy as np i = np.arange(2,4) a = np.arange(5) a_slice = a[:] print(np.shares_memory(a, a_slice)) # 输出 True,说明是视图 b = np.arange(5) b_indexed = b[i] print(np.shares_memory(b, b_indexed)) # 输出 False,说明是副本
也可以用id()辅助理解:id(a[:])和id(a)不同是因为视图是新的数组对象,但它的底层数据缓冲区和原数组共享;而b[i]的id()和b不同,且底层数据缓冲区完全独立,所以修改它不影响原数组。
内容的提问来源于stack exchange,提问作者Daniel Reese
相关产品推荐
相关产品推荐

