在操作数组的时候返回的不是视图就是副本。

副本:复制

视图:链接

 

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

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

 

视图一般发生在:

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

副本一般发生在:

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

 

赋值

赋值操作,两个变量a, b都指向同一个内存地址, b与原始数组a的id()相同。 id()返回 Python 对象的通用标识符,类似于 C 中的指针。

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

import numpy as np

a = np.arange(6)
b = a
print('数组a:',a)
print('数组b:',b)

print('a 调用 id() 函数:',id(a))
print('b 调用 id() 函数:',id(b))

b.shape = 3, 2
print('修改 b 的形状:')
print(b)
print('a 的形状也修改了:')
print(a)

输出结果为:

数组a: [0 1 2 3 4 5]
数组b: [0 1 2 3 4 5]
a 调用 id() 函数: 2026424909056
b 调用 id() 函数: 2026424909056


修改 b 的形状:
[[0 1]
[2 3]
[4 5]]


a 的形状也修改了:
[[0 1]
[2 3]
[4 5]]

 

视图或浅拷贝

Numpy的切片操作会返回原数据的视图,切片产生的视图是原视图的一部分视图,对视图的修改会直接反映到原数据中,但它们的id是不同的。也就是说,视图虽然指向原数据,但是他们和赋值引用还是有区别的。

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

import numpy as np

# 最开始 a 是个 3X2 的数组
a = np.arange(6).reshape(3, 2)
print('数组 a:')
print(a)
print('\n')

b = a.view()
print('创建 a 的视图b:')
print(b)
print('\n')

print('a 的 id():',id(a))
print('b 的 id():',id(b))
print('\n')

# 修改 b 的形状,并不会修改 a
b.shape = 2, 3
print('修改形状后的b:')
print(b)
print('\n')

print('修改b形状后的a:')
print(a)

输出结果为:

数组 a:
[[0 1]
[2 3]
[4 5]]


创建 a 的视图b:
[[0 1]
[2 3]
[4 5]]


a 的 id(): 1601808711552
b 的 id(): 1601809504256


修改形状后的b:
[[0 1 2]
[3 4 5]]


修改b形状后的a:
[[0 1]
[2 3]
[4 5]]

 

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

import numpy as np

arr = np.arange(12)
print('我们的数组:',arr)
print('\n')

a = arr[3:]
b = arr[3:]
print('切片a:',a)
print('切片b:',b)
print('\n')

a[1] = 123
b[2] = 234
print('修改后的数组arr:')
print(arr)
print('修改后的数组a:')
print(a)
print('修改后的数组b:')
print(b)
print('\n')


print('a的id:',id(a))
print('b的id:',id(b))
print('arr的id:',id(arr))

输出结果为:

我们的数组: [ 0 1 2 3 4 5 6 7 8 9 10 11]


切片a: [ 3 4 5 6 7 8 9 10 11]
切片b: [ 3 4 5 6 7 8 9 10 11]


修改后的数组arr:
[ 0 1 2 3 123 234 6 7 8 9 10 11]
修改后的数组a:
[ 3 123 234 6 7 8 9 10 11]
修改后的数组b:
[ 3 123 234 6 7 8 9 10 11]


a的id: 1173376024448
b的id: 1173376023968
arr的id: 1173376023888

 

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

 

副本或深拷贝

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

import numpy as np

a = np.array([[10, 10], [2, 3], [4, 5]])
print('数组 a:')
print(a)
print('\n')

b = a.copy()
print('创建 a 的副本数组 b:')
print(b)
print('\n')

# b 与 a 不共享任何内容
print('我们能够写入 b 来写入 a 吗?')
print(b is a)
print('\n')


b[0, 0] = 100
print('修改副本b:')
print(b)
print('\n')

print('修改副本b后,a数组不变:')
print(a)

输出结果为:

数组 a:
[[10 10]
[ 2 3]
[ 4 5]]


创建 a 的副本数组 b:
[[10 10]
[ 2 3]
[ 4 5]]


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


修改副本b:
[[100 10]
[ 2 3]
[ 4 5]]


修改副本b后,a数组:
[[10 10]
[ 2 3]
[ 4 5]]