在 Python 中, 经常要对一个 list 进行复制. 对于复制, 自然的就有深拷贝与浅拷贝问题. 深拷贝与浅拷贝的区别在于, 当从原本的 list 复制出新的 list 之后, 修改其中的任意一个是否会对另一个造成影响, 即这两个 list 在内存中是否储存在同一个区域, 这也是区分深拷贝与浅拷贝的重要依据. 接下来我们就针对 Python 中 list 复制的几种方法, 来探究一下其是属于深拷贝还是浅拷贝. 弄清楚这个问题, 有助于我们在编程中规避错误, 减少不必要的调试时间.
一, 非拷贝方法 -- 直接赋值
如果用 = 直接赋值, 是非拷贝方法. 这两个列表是等价的, 修改其中任何一个列表都会影响到另一个列表. 这也是 Python 作为动态语言与 C 这类静态语言在思想上的不同之处.
- #!/usr/bin/env python3
- # -*- coding: utf-8 -*-
- old = [1, [1, 2, 3], 3]
- new = old
- print('Before:')
- print(old)
- print(new)
- new[0] = 3
- new[1][0] = 3
- print('After:')
- print(old)
- print(new)
运行结果:
二, 浅拷贝的几种方法
1.copy()方法
我们来看以下代码:
- #!/usr/bin/env python3
- # -*- coding: utf-8 -*-
- old = [1, [1, 2, 3], 3]
- new = old.copy()
- print('Before:')
- print(old)
- print(new)
- new[0] = 3
- new[1][0] = 3
- print('After:')
- print(old)
- print(new)
运行结果:
对于 list 的第一层, 是实现了深拷贝, 但对于嵌套的 list, 仍然是浅拷贝. 这其实很好理解, 内层的 list 保存的是地址, 复制过去的时候是把地址复制过去了. 嵌套的 list 在内存中指向的还是同一个.
2. 使用列表生成式
使用列表生成式产生新列表也是一个浅拷贝方法, 只对第一层实现深拷贝.
- #!/usr/bin/env python3
- # -*- coding: utf-8 -*-
- old = [1, [1, 2, 3], 3]
- new = [i for i in old]
- print('Before:')
- print(old)
- print(new)
- new[0] = 3
- new[1][0] = 3
- print('After:')
- print(old)
- print(new)
运行结果:
3. 用 for 循环遍历
通过 for 循环遍历, 将元素一个个添加到新列表中. 这也是一个浅拷贝方法, 只对第一层实现深拷贝.
- #!/usr/bin/env python3
- # -*- coding: utf-8 -*-
- old = [1, [1, 2, 3], 3]
- new = []
- for i in range(len(old)):
- new.append(old[i])
- print('Before:')
- print(old)
- print(new)
- new[0] = 3
- new[1][0] = 3
- print('After:')
- print(old)
- print(new)
运行结果:
4. 使用切片
通过使用 [:] 切片, 可以浅拷贝整个列表. 同样的, 只对第一层实现深拷贝.
- #!/usr/bin/env python3
- # -*- coding: utf-8 -*-
- old = [1, [1, 2, 3], 3]
- new = old[:]
- print('Before:')
- print(old)
- print(new)
- new[0] = 3
- new[1][0] = 3
- print('After:')
- print(old)
- print(new)
运行结果:
三, 深拷贝的实现
如果用 deepcopy()方法, 则无论多少层, 无论怎样的形式, 得到的新列表都是和原来无关的, 这是最安全最清爽最有效的方法.
使用时, 要导入 copy.
- #!/usr/bin/env python3
- # -*- coding: utf-8 -*-
- import copy
- old = [1, [1, 2, 3], 3]
- new = copy.deepcopy(old)
- print('Before:')
- print(old)
- print(new)
- new[0] = 3
- new[1][0] = 3
- print('After:')
- print(old)
- print(new)
运行结果:
以上, 就是对 list 的复制及深拷贝与浅拷贝探究. 鉴于本人水平有限, 文中有不妥之处, 还请在评论中指出.
来源: https://www.cnblogs.com/Bil369/p/9575659.html