副本和视图
副本是一个队数据的完整的拷贝,如果对副本进行修改,不会影响原始数据,因为物理地址不在同一位置.
视图是数据的一个别称或引用,通过该别称或引用便可访问、操作原有数据,单原有数据不会产生拷贝。如果对视图进行修改,会影响原始数据,因为物理内存在同一位置。
视图一般发生在:
- numpy的切片操作返回原始数据的视图
- 调用 ndarray的 view()函数产生一个视图
副本一般发生在:
- python 序列的切片操作,调用 deepcopy()函数
- 调用 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]]