在python中,对一个变量赋值实际上是将这个值的引用赋给变量,在这里涉及到两种拷贝方式:浅拷贝和深拷贝。
浅拷贝
创建一个新的对象,这个对象中的元素仍然是原对象中的元素,即元素的地址一样。
浅拷贝方法:
1、完全切片操作 [:]
2、工厂函数 (如 list、dict)
3、copy方法
例子:首先看一下浅拷贝之后新对象和原对象的地址
import copy
arr_1 = [[3, 'str'], ['s', 10]]
arr_2 = copy.copy(arr_1)
id(arr_1), id(arr_2)
(812683685640, 812683682056)
浅拷贝创建的是新的对象,所以arr_1和arr_2的地址不一样。
接着看新的对象中各元素的地址:
[id(x) for x in arr_1],[id(x) for x in arr_2]
([812683618248, 812683682184],
[812683618248, 812683682184])
对应元素的地址都是一样的,说明浅拷贝只是创建了新的对象,但是对象中的元素的原来的元素的引用还是一样的,即共用同一个引用。
针对浅拷贝,我们发现如果更改了新对象中元素的值,原对象不会有影响,但若是更改的是新对象中元素的元素,则原对象也一样会被更改。
arr_2[0] = 1 # 更改新对象的元素
arr_1,arr_2
([[3, 'str'], ['s', 10]],
[1, ['s', 10]])
arr_2[1][1] = 100 # 更改新对象的元素的元素
arr_1,arr_2
([[3, 'str'], ['s', 100]],
[1, ['s', 100]])
[id(x) for x in arr_1],[id(x) for x in arr_2]
([812683637128, 812683638024],
[1683554800, 812683638024])
在这里,更改新对象的元素,是将一个引用赋给对象的元素的对应位置,而新对象和原对象的地址不同,代表的不是同一个引用,所以更改新对象的元素,对原对象没有什么影响,注意这里说的更改是指将值或其他变量的引用赋给这个元素,并不包括使用函数更改的情况。
当更改对象元素的元素的时候,因为新对象和原对象的元素的引用是一样的,所以更改其中一个对象的元素的元素,同时也会更改到另外一个对象。
深拷贝
完全的拷贝,新对象和原对象不会互相影响,可以理解为两者完全没有关系
深拷贝方法:deepcopy方法
例子:
import copy
arr_1 = [[3, 'str'], ['s', 10]]
arr_2 = copy.deepcopy(arr_1)
id(arr_1), id(arr_2)
(812681300488, 812683687880)
新对象和原对象的地址不一样
接下来看元素的地址:
[id(x) for x in arr_1],[id(x) for x in arr_2]
([812683687432, 812683686728],
[1683554800, 812683686600])
arr_2[0] = 1
arr_1,arr_2
([[3, 'str'], ['s', 10]],
[1, ['s', 10]])
arr_2[1][1] = 100
arr_1,arr_2
([[3, 'str'], ['s', 10]],
[1, ['s', 100]])
元素的地址也不一样,说明新对象和原对象不会互相影响。
注意当元素为不可变类型(比如字符串,元组)时,这类元素的地址仍然是一样的,但这并不会有影响,因为不可变类型无法更改,除非是重新赋值。
综上,浅拷贝是对对象的拷贝,而深拷贝是对对象包括元素的拷贝。
版权声明:本文为博主原创文章,未经博主允许不得转载。