Python 深拷贝和浅拷贝
前言
在写某个脚本时,用了DFS(深度有限遍历)算法判断两个点的可达性,并传入参数trace记录路径,如下因为直接采用赋值形式,导致函数逻辑错误(cur_trace改变的时候,trace也改变了),这才了解到在Python中存在赋值、浅拷贝和深拷贝的区别。
相关概念
在了解赋值、深浅拷贝之前,先来了解以下概念:
对象:
- 不可变对象:一旦创建就不可修改的对象,如数值(int, float)、字符串、元组是不可变对象。
- 可变对象:对象本身可变,如列表、字典、集合。
引用:在python中,新建一个变量都是在为某个对象新增一个引用,引用本身不占有内存空间,只是对对象的一个指向(别名)。如下图,在a=2中,2是一个对象,a是对2这个对象的一个引用。
赋值
方法:“=”
特点:赋值就是对对象的引用,不开辟新的内存空间。如下,b=a只是对a所指的对象增加一个引用b,a和b指向同一个对象。
当改变b时:a也会改变。
浅拷贝
方法:
- 切片操作:b = a[:]
- 列表生成式:b = [ _ for _ in a]
- 工厂函数:b = list(a)
- copy()函数:b = a.copy()
特点:开辟新内存空间,拷贝父对象,但不拷贝对象内部的子对象,子对象仍然是引用。如下,b=a.copy()后b只拷贝了a的第一层,元素是对象就拷贝了对象,元素是引用就拷贝了引用。
当b改变时:
- b中对不可变对象的修改不影响a
1
2
3b[0]=2
print(b) # [2,[2,3,4]]
print(a) # [1,[2,3,4]]- b中对可变对象的修改会导致a中也改变
1
2
3b[1].append(5)
print(b) # [1,[2,3,4,5]]
print(a) # [1,[2,3,4,5]]
深拷贝
方法:用copy模块中的deepcopy()函数,b = copy.deepcopy(a)
特点:开辟新内存空间,递归拷贝对象全部内容,包括父对象及其子对象。
当b改变时:改变b中父对象或子对象均不影响a,二者完全独立。
总结
其实其他语言如Java、JS等中也有这一概念,看了一下,其定义基本相同。最后总结一下赋值、浅拷贝和深拷贝区别:
类型 | 是否开辟新内存空间 | 子对象不可变时,改变子对象 | 子对象可变时,改变子对象 |
---|---|---|---|
赋值 | 否 | 原数据也改变 | 原数据也改变 |
浅拷贝 | 是 | 原数据不改变 | 原数据也改变 |
深拷贝 | 是 | 原数据不改变 | 原数据不改变 |
参考文章
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 只取壹瓢饮!