为何np.split向已有数组赋值时会创建副本?
关于NumPy中np.split视图与副本的疑问
我是Python新手,正在学习视图(view)与副本(copy)的特性,若问题浅显还请见谅!以下示例中,我使用np.split()拆分数组x:
当将np.split结果赋值给新对象(如包含3个一维数组的列表x1,或三个独立一维数组x2、x3、x4)时,这些对象都是x的视图,符合预期:
import numpy as np x = np.arange(1, 10) # 创建长度为9的数组 x1 = np.split(x, (3,6)) # 将数组拆分为一个新对象(数组列表) print(x1[0].base) # 列表中的每个数组都是视图 x2, x3, x4 = np.split(x, (3, 6)) # 将数组拆分为三个新对象 print(x2.base) # 这些对象是视图
但当我创建一个空的(3,3)数组x5,并将np.split结果赋值给x5的每一行时(我知道这操作无意义,只是想理解拆分机制),却创建了副本:
x5 = np.empty((3,3), dtype = np.int32) # 创建未初始化数组 x5[0], x5[1], x5[2] = np.split(x, (3, 6)) # 将x拆分后赋值给x5的每一行 print(x5.base) # 该对象是副本
我原以为是x5的切片导致副本生成,但对x2、x3、x4进行切片赋值时,它们仍为视图:
x2[:], x3[:], x4[:] = np.split(x, (3, 6)) # 用索引将数组拆分后赋值给三个已有对象 print(x2.base) # 这些对象仍是视图
我在视图与副本或np.split的相关资料中未找到解释,请问我忽略了什么?
核心原因解析
这两种赋值操作的本质区别在于目标对象的内存是否独立于原数组:
np.split直接赋值给新变量:np.split返回的是原数组的切片视图,这些视图本身不存储数据,只是指向原数组x的内存区域。当你把它们赋值给x1、x2等变量时,变量只是保存了这些视图的引用,自然和原数组共享内存。- 赋值给
x5的行切片:x5是独立创建的新数组,有自己的内存空间。执行x5[0] = np.split(...)时,本质是把视图中的数据拷贝到x5已分配好的内存位置里,相当于复制了一份原数组的数据到x5的内存中,所以x5和原数组完全独立,是副本。 - 对
x2[:]的切片赋值:x2本身已经是原数组的视图,x2[:]指向的是x2对应的原数组内存区域。这种赋值是直接修改视图指向的原数组数据,没有创建新内存空间,所以x2依然是原数组的视图。
简单总结:直接接收np.split返回值拿到的是原数组的"窗口"(视图);把视图数据写到独立数组的内存里会生成副本;对已有视图的切片赋值只是修改原数组数据,视图属性不变。
内容的提问来源于stack exchange,提问作者Lucy Wheeler
相关产品推荐
相关产品推荐

