NumPy 副本和视图 - NUMPY教程

NumPy 副本和视图

副本是一个数据的完整的拷贝,如果我们对副本进行修改,它不会影响到原始数据,物理内存不在同一位置。

视图是数据的一个别称或引用,通过该别称或引用亦便可访问、操作原有数据,但原有数据不会产生拷贝。如果我们对视图进行修改,它会影响到原始数据,物理内存在同一位置。

视图一般发生在:

  • 1、numpy 的切片操作返回原数据的视图。
  • 2、调用 ndarray 的 view() 函数产生一个视图。

副本一般发生在:

  • Python 序列的切片操作,调用deepCopy()函数。
  • 调用 ndarray 的 copy() 函数产生一个副本。

无复制

简单的赋值不会创建数组对象的副本。 相反,它使用原始数组的相同id()来访问它。 id()返回 Python 对象的通用标识符,类似于 C 中的指针。

此外,一个数组的任何变化都反映在另一个数组上。 例如,一个数组的形状改变也会改变另一个数组的形状。

示例代码
importnumpyasnpa=np.arange(6)print('我们的数组是:')print(a)print('调用 id() 函数:')print(id(a))print('a 赋值给 b:')b=aprint(b)print('b 拥有相同 id():')print(id(b))print('修改 b 的形状:')b.shape=3,2print(b)print('a 的形状也修改了:')print(a)

输出结果为:

我们的数组是:

[0 1 2 3 4 5]

调用 id() 函数:

4349302224

a 赋值给 b:

[0 1 2 3 4 5]

b 拥有相同 id():

4349302224

修改 b 的形状:

[[0 1]

 [2 3]

 [4 5]]

a 的形状也修改了:

[[0 1]

 [2 3]

 [4 5]]

视图或浅拷贝

ndarray.view() 方会创建一个新的数组对象,该方法创建的新数组的维数变化不会改变原始数据的维数。

示例代码
importnumpyasnp# 最开始 a 是个 3X2 的数组a=np.arange(6).reshape(3,2)print('数组 a:')print(a)print('创建 a 的视图:')b=a.view()print(b)print('两个数组的 id() 不同:')print('a 的 id():')print(id(a))print('b 的 id():')print(id(b))# 修改 b 的形状,并不会修改 ab.shape=2,3print('b 的形状:')print(b)print('a 的形状:')print(a)

输出结果为:

数组 a:

[[0 1]

 [2 3]

 [4 5]]

创建 a 的视图:

[[0 1]

 [2 3]

 [4 5]]

两个数组的 id() 不同:

a 的 id():

4314786992

b 的 id():

4315171296

b 的形状:

[[0 1 2]

 [3 4 5]]

a 的形状:

[[0 1]

 [2 3]

 [4 5]]

使用切片创建视图修改数据会影响到原始数组:

示例代码
importnumpyasnparr=np.arange(12)print('我们的数组:')print(arr)print('创建切片:')a=arr[3:]b=arr[3:]a[1]=123b[2]=234print(arr)print(id(a),id(b),id(arr[3:]))

输出结果为:

我们的数组:

[ 0  1  2  3  4  5  6  7  8  9 10 11]

创建切片:

[  0   1   2   3 123 234   6   7   8   9  10  11]

4545878416 4545878496 4545878576

变量 a,b 都是 arr 的一部分视图,对视图的修改会直接反映到原数据中。但是我们观察 a,b 的 id,他们是不同的,也就是说,视图虽然指向原数据,但是他们和赋值引用还是有区别的。

副本或深拷贝

ndarray.copy() 函数创建一个副本。 对副本数据进行修改,不会影响到原始数据,它们物理内存不在同一位置。

示例代码
importnumpyasnpa=np.array([[10,10],[2,3],[4,5]])print('数组 a:')print(a)print('创建 a 的深层副本:')b=a.copy()print('数组 b:')print(b)# b 与 a 不共享任何内容print('我们能够写入 b 来写入 a 吗?')print(bisa)print('修改 b 的内容:')b[0,0]=100print('修改后的数组 b:')print(b)print('a 保持不变:')print(a)

输出结果为:

数组 a:

[[10 10]

 [ 2  3]

 [ 4  5]]

创建 a 的深层副本:

数组 b:

[[10 10]

 [ 2  3]

 [ 4  5]]

我们能够写入 b 来写入 a 吗?

False

修改 b 的内容:

修改后的数组 b:

[[100  10]

 [  2   3]

 [  4   5]]

a 保持不变:

[[10 10]

 [ 2  3]

 [ 4  5]]

更多相关文章

Python 直接赋值、浅拷贝和深度拷贝解析