副本和视图

副本是一个队数据的完整的拷贝,如果对副本进行修改,不会影响原始数据,因为物理地址不在同一位置.

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

视图一般发生在:

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

副本一般发生在:

  1. python 序列的切片操作,调用 deepcopy()函数
  2. 调用 ndarray的 copy()函数产生一个副本

无复制

简单的赋值不会创建数组对象的副本

num_np = np.arange(6)
print(f'原始数组:{num_np}')  # 输出结果: 原始数组:[0 1 2 3 4 5]
print(f'原始数组 id:{id(num_np)}')  # 输出结果: 原始数组 id:140405965918736

b_np.shape = (3,2)

print(f'修改后的数组:{b_np}')

# 输出结果:
#  修改后的数组:[[0 1]
#   [2 3]
#   [4 5]]
print(f'修改后的 num_np:{num_np}')

# 输出结果:
#  修改后的 num_np:[[0 1]
#   [2 3]
#   [4 5]]

视图

ndarray.view()函数会创建一个新的数组对象,该函数创建的新数组的维度更改不会更改原始数组的维度

num_np = np.arange(6)
print(f'原始数组:{num_np}')  # 输出结果: 原始数组:[0 1 2 3 4 5]
b_np = num_np.view()
print(f'num_np的视图:{b_np}')  # 输出结果:  num_np的视图:[0 1 2 3 4 5]
print(f'原始数组 id:{id(num_np)}')  # 输出结果: 原始数组 id:140405616499648
print(f'新数组的 id:{id(b_np)}')  # 输出结果:  新数组的 id:140405623037264
b_np.shape = (2,3)
print(f'num_np 的形状:{num_np}')

# 输出结果:
#  num_np 的形状:[0 1 2 3 4 5]
print(f'b_np 的形状:{b_np}')

# 输出结果:
#  b_np 的形状:[[0 1 2]
#   [3 4 5]]

使用切片创建视图修改数据会影响初识数组:

arr = np.arange(12)
print(f'初识数组:{arr}')  # 输出结果: 初识数组:[ 0  1  2  3  4  5  6  7  8  9 10 11]
a_np = arr[3:]
b_np = arr[3:]
a_np[1] = 123
b_np[2] = 456
print(arr)  # 输出结果: [  0   1   2   3 123 456   6   7   8   9  10  11]
print(id(a_np), id(b_np), id(arr[3:]))  # 输出结果: 140405625962784 140405625965264 140405625965344

副本

ndarray.copy()函数用于创建一个副本

对副本数据进行修改不会影响原始数据,原始数据和副本的物理内存不在同一位置

a_np = np.array([[10,10],[2,3],[4,5]])
print(f'原数组:{a_np}')

# 输出结果:
#  原数组:[[10 10]
#   [ 2  3]
#   [ 4  5]]
b_np = a_np.copy()
print(f'a_np 和 b_np是否相同:{b_np is a_np}')

# 输出结果:
a_np 和 b_np是否相同:False

b_np[0,0] = 100
print(f'修改后的数组:\n{b_np}')
# 输出结果:
#  修改后的数组:
#  [[100  10]
#   [  2   3]
#   [  4   5]]


print(f'a_np数组:{a_np}')
# 输出结果:
#  a_np数组:[[10 10]
#   [ 2  3]
#   [ 4  5]]