在操做數組的時候返回的不是視圖就是副本。python

副本:複製web

視圖:連接數組

 

副本是一個數據的完整拷貝,若是咱們對副本進行修改,它不會影響到原始數據,物理內存不在同一位置。app

視圖是數據的一個別稱或引用,經過該別稱或引用亦可訪問、操做原有數據,但原有數據不會產生拷貝。若是咱們對視圖進行修改,它會影響到原始數據,物理內存在同一位置。ide

 

視圖通常發生在:函數

  • 一、numpy 的切片操做返回原數據的視圖。
  • 二、調用 ndarray 的 view() 函數產生一個視圖。

副本通常發生在:工具

  • Python 序列的切片操做,調用deepCopy()函數。
  • 調用 ndarray 的 copy() 函數產生一個副本。

 

賦值

賦值操做,兩個變量a, b都指向同一個內存地址, b與原始數組a的id()相同。 id()返回 Python 對象的通用標識符,相似於 C 中的指針。post

一個數組的任何變化都反映在另外一個數組上。 例如,一個數組的形狀改變也會改變另外一個數組的形狀。spa

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]]