第一步:重点理解可变对象与不可变对象的概念,本质改变值是否会开辟新的id地址问题,也就是指针指向对象是否会更改;
赋值语句:
a = 'python'
第二步:赋值、浅拷贝、深拷贝三者之间的区别:
赋值:就是复制了所有引用,相当于给源对象起别名。
例如,a = 'python',b = a,给'python'起别名b,所有id地址一样,包含子对象地址。
浅拷贝:指重新分配一块内存,创建一个新的对象,里面的元素是原对象中子对象的引用(即拷贝父对象,不会拷贝对象的内部的子对象)。
注意,此处要对原对象中的子对象类型作情况讨论。
没有对原对象的所有内部对象进行复制引用,仅对外层子对象复制,所以叫浅拷贝。
新对象的id地址与原对象不同,但是其子对象地址引用有部分相同,具体视子对象的可变或不可变类型而不同——这里关联到第一步所讲的可变对象和不可变对象的概念:
若子对象为可变类型,作出赋值更改时,子对象的值会更改而不是开辟新内存地址,即不更改子对象的id地址,故新对象也会跟着同步更新;反之,子对象为不可变类型,则会开辟新的内存地址,原对象的子对象指向新的id地址,但是新对象的子对象还是指向原来的id地址,所以不会同步更新。
浅拷贝有三种形式: 切片操作,列表解析,工厂函数,copy模块中的copy函数。
如: a = [1,2,[3,4]]
切片操作:b = a[:]
列表解析式:b = [ i for i in a ]
工厂函数:b = list(a)
copy函数:b = copy.copy(a)
浅拷贝中的元素,是原对象中子对象的引用,因此,如果原对象中的元素是可变的,改变其也会影响拷贝后的对象,存在一定的副作用。
深拷贝:完全拷贝了父对象及其子对象,深拷贝出来的对象是一个全新的对象,不再与原来的对象有任何关联。
完整地对原对象进行复制引用(包含多层嵌套的对象),新对象产生新的id地址,子对象若为可变类型则会开辟新的id地址,否则仍指向旧的id地址。同样的,结合第一步的可变对象和不可变对象的赋值概念会更容易理解。
Python 中以copy 模块的 deepcopy 方法,来实现对象的深度拷贝,例如b = copy.copy(a)。
深度拷贝也不是完美的,往往也会带来一系列问题。如果被拷贝对象中存在指向自身的引用,那么程序很容易陷入无限循环:
import copy
x = [1]
x.append(x)
x
[1, [...]]
y = copy.deepcopy(x)
y
[1, [...]]
最后,附几张图方便理解:
个人思路,供参考,若有错误,欢迎指正。
参考:
https://zhuanlan.zhihu.com/p/54011712
https://zhuanlan.zhihu.com/p/152244101
https://www.runoob.com/w3cnote/python-understanding-dict-copy-shallow-or-deep.html