python numpy append_浅析Python中的numpy copy和view,以及append()和deep copy、浅拷贝,NumPy,副本,视图,与,深...

NumPy 副本和视图

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

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

视图一般发生在:

1、numpy 的切片操作返回原数据的视图。

2、调用 ndarray 的 view() 函数产生一个视图。

副本一般发生在:

Python 序列的切片操作,调用deepCopy()函数。

调用 ndarray 的 copy() 函数产生一个副本。

无复制

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

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

import numpy as np

a = np.arange(6)

print ('我们的数组是:')

print (a)

print ('调用 id() 函数:')

print (id(a))

print ('a 赋值给 b:')

b = a

print (b)

print ('b 拥有相同 id():')

print (id(b))

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

b.shape = 3,2

print (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() 方会创建一个新的数组对象,该方法创建的新数组的维数更改不会更改原始数据的维数。

import numpy as np

# 最开始 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 的形状,并不会修改 a

b.shape = 2,3

print ('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]]

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

import numpy as np

arr = np.arange(12)

print ('我们的数组:')

print (arr)

print ('创建切片:')

a=arr[3:]

b=arr[3:]

a[1]=123

b[2]=234

print(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() 函数创建一个副本。 对副本数据进行修改,不会影响到原始数据,它们物理内存不在同一位置。

import numpy as np

a = 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 (b is a)

print ('修改 b 的内容:')

b[0,0] = 100

print ('修改后的数组 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 中,对象赋值实际上是对象的引用。当创建一个对象,然后把它赋给另一个变量的时候,Python 并没有拷贝这个对象,而只是拷贝了这个对象的引用,我们称之为浅拷贝。

在 Python 中,为了使当进行赋值操作时,两个变量互补影响,可以使用 copy 模块中的 deepcopy 方法,称之为深拷贝。

append() 函数

当 list 类型的对象进行 append 操作时,实际上追加的是该对象的引用。

id()

函数:返回对象的唯一标识,可以类比成该对象在内存中的地址。

>>>alist = []

>>> num = [2]

>>> alist.append( num )

>>> id( num ) == id( alist[0] )

True

如上例所示,当 num 发生变化时(前提是 id(num) 不发生变化),alist 的内容随之会发生变化。往往会带来意想不到的后果,想避免这种情况,可以采用深拷贝解决:

alist.append( copy.deepcopy( num ) )

PS:

id()函数:返回对象的唯一标识,可以类比成该对象在内存中的地址。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值