Python中的赋值、视图、副本与拷贝
数组对象在创建后会存在唯一标识数组内容的通用标识符(即id值)与其数组内容在内存中的存储地址,通过不同方式创建基于原数组的新数组会在这两个属性的基础上产生不同的结果。
赋值与无拷贝
将原数组直接赋值给新数组后,新数组同原数组的标识符与存储地址一致。因此,新数组可以粗略理解为完全通过原数组访问。因此在直接赋值过程中并未创建拷贝。
1 | a = np.array([[1, 2, 3], [3, 4, 5]]) |
视图与浅拷贝
在numpy中对原数组(ndarray)进行切片操作或通过view()
方法创建视图后,新数组同原数组的存储地址一致但标识符不一致。介于numpy在进行切片操作时直接操作了原数组,产生的新数组虽变更了标识符,但实际将原数组所在内存地址引用并赋值给了新数组,因此新数组仍基于原数组的存储地址进行内容访问。因此,修改新数组中的数据内容会直接影响并同步给原数组,但诸如变形之类的操作则不会。
1 | a = np.array([[1, 2, 3], [3, 4, 5]]) |
副本与深拷贝
对python序列(tuple)或列表(list)等对象进行切片操作、通过deepCopy()
方法创建深拷贝或在numpy中通过copy()
方法创建副本后,新数组同原数组的存储地址一致与标识符均不一致,两者之间相互独立。介于python进行切片操作时首先调用deepCopy()
方法复制了原数组的深拷贝,然后再在该拷贝上进行操作,因此两者互不相关。
1 | a = [1, 2, 3, 4, 5] |
python列表(list)对象进行append()
操作时,实际进行了直接拷贝。
1 | list1 = [1, 2] |
因此,若要避免因修改变量值导致的数组数据变化,可通过深拷贝解决。
1 | list1 = [1, 2] |
值得注意的是,numpy的ndarray对象进行append()
操作需要将结果赋给其他的对象,因此经扩展后生成的新数组与原数组无关,所扩展的值与新数组中的对应扩展元素也无关。
1 | list1 = np.array([1, 2]) |
总结
操作 | 拷贝类型 | 标识符 | 内存地址 |
---|---|---|---|
直接赋值 | 无 | 一致 | 一致 |
numpy切片 | 浅拷贝 | 不同 | 一致 |
python切片 | 深拷贝 | 不同 | 不同 |
view() 方法 |
浅拷贝 | 不同 | 一致 |
copy() 方法 |
深拷贝 | 不同 | 不同 |
- Title: Python中的赋值、视图、副本与拷贝
- Author: Zielorem
- Created at : 2022-10-19 14:47:15
- Updated at : 2023-07-14 01:06:24
- Link: https://zielorem.github.io/2022/10/19/view-and-copy/
- License: This work is licensed under CC BY-NC-SA 4.0.
Comments