赋值
|
|
a
赋值给 b
就是将变量 b
的引用指向 a
, 因此变量 a
与 b
的内存地址相同,a,b
中元素的地址也相同。所以改变a[0],a[2]
中的值, 变量 b
也对应着改变。a[0]
的字符串是不可变类型,改变其值需要新开辟一段内存空间。
浅拷贝
|
|
浅拷贝会创建一个新的对象,然后把生成的新对象赋值给新变量。但是对象里的元素依然按引用传递,由第 12 和 13行 可以看出,元素的内存地址并没有改变,只是变量 a
和 b
的内存地址不同。也就是说浅拷贝为对象开辟了新的内存空间,但是对象里的元素依然按照引用传递。由于 a[0]
里的元素字符串是不可变类型,改变其值需要另开辟一段内存空间,而 b[0]
的引用依然指向原地址,所以改变 a[0]
的值并不影响b[0]
的值。a[2]
是可变类型,可以原地改变值,不需要另外开辟新的内存空间,所以 b[2]
的值随着 a[2]
的改变而改变,而内存地址并不需要改变。
切片[:]
操作,list/dir/set
以及 copy()
函数都属于浅拷贝。
深拷贝
|
|
深拷贝与浅拷贝类似,也是创建一个新的对象,然后把生成的新对象赋值给新变量。但是对原对象元素的操作不同,由第11和13行可以看出,对于不可变元素,深拷贝依然使用引用方式,可变类型元素则新开辟一段内存空间,因为改变不可变类型的元素,需要开辟新的内存空间,而深拷贝的引用还是指向原地址,所以原对象改变其值并不影响深拷贝的值。对于可变类型的元素,深拷贝后元素的内存地址与原对象值的内存地址并不相同,因此两个值的改变与否没有任何关系。
总结
- Python 中对象的赋值都是进行对象引用(内存地址)传递
- 对于赋值,两个对象内的元素相互影响,本质上是同一个内存空间,只是在有两个不同的标签而已
- 对于浅拷贝,它复制了对象,但对于对象中的元素,依然使用原始引用。改变原对象不可改变类型的元素,不会影响拷贝后对象相应的值。改变原对象可变类型元素的值,浅拷贝后对象的值相应也会改变
- 对于深拷贝,可以把两个对象看成独立的对象,元素的改变在彼此之间没有任何影响。值得注意的是,对于不可变类型的元素,深拷贝后对象相应元素的内存地址与原对象的相同,而可变类型元素的则不同。从第11和13行可以看,
a[0],b[0]
以及a[1],b[1]
的地址相同,而a[2]
与b[2]
则不同