Python—list 和 dict 的复制

元素复制(针对 list)

一个 list 乘上一个整数 n 表示重复 list 中的元素 n 次创建一个新 list。这里需要注意的是 n ≥ 0,如果 n < 0,返回新的空 list,可以看下面的示例。

复制代码
>>> [0, 1] * 2
[0, 1, 0, 1]
>>> [0, 1] * 1
[0, 1]
>>> [0, 1] * 0
[]
>>> [0, 1] * -1
[]
>>> [0, 1] * -2
[]

由此可以得出,创建 10 个元素全为 0 的 list 可以这么做:[0] * 10,看一下是不是彻底实现了复制。

复制代码
>>> a = [0] * 10
>>> a
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
>>> a[0] = 1
>>> a
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0]

可以看到实现了复制,修改第一个元素的值对其余的元素没有影响。然而,事情可能没有那么简单,再来看一个例子。

复制代码
>>> a = [[]] * 10
>>> a
[[], [], [], [], [], [], [], [], [], []]
>>> a[0].append(0)
>>> a
[[0], [0], [0], [0], [0], [0], [0], [0], [0], [0]]

可以发现,结果并不是想要的,一改全改。可以发现乘法有些时候不能进行复制。与此同时,希望大 list 里面的小 list 也实现复制,而不是指向同一个,怎么做?很简单,使用列表推导式就可以了,还是这个例子。

复制代码
>>> a = [[] for _ in range(10)]
>>> a
[[], [], [], [], [], [], [], [], [], []]
>>> a[0].append(0)
>>> a
[[0], [], [], [], [], [], [], [], [], []]

这下应该没有问题了。如果进行元素复制怕遇到这样的麻烦就全部使用列表推导式。乘法也要会,因为有些模块或者是项目的源码可能会使用乘法!

整体复制

因为整体复制针对 list 和 dict 都可以使用,所以分成两部分,先看 list 的整体复制,再看 dict 的整体复制。

list 整体复制

假设有一个 list 的实例 a,要把它复制给 b,能不能直接写 b = a 呢?其实是不行的,可以看一下下面的示例。

复制代码
>>> a = [1, 2, 1]
>>> b = a
>>> b[2] = 3
>>> a
[1, 2, 3]

可以发现,修改 b 的时候,a 也跟着改了,可以看出 a 和 b 是同一个 list,如何让 a 和 b 只是值相等,但它们是不同的 list 呢?

最容易想到的方法就是使用 list 的方法 copy,还是这个例子。

复制代码
>>> a = [1, 2, 1]
>>> b = a.copy()
>>> b[2] = 3
>>> a
[1, 2, 1]

可以发现修改 b 对 a 没有任何影响,因此完成了复制。

完成复制的操作其核心代码就是第二行,还可以使用下面几种方法来完成复制。

复制代码
>>> b = a[:]
>>> b = list(a)
>>> b = [_ for _ in a]
>>> b = a + []  # 写成 b = [] + a 也可以
>>> b = a * 1  # 写成 b = 1 * a 也可以

其中后面两种可能不是那么容易能够想得到的,这些方法都能完成复制,可以自己进行验证。

但是,这几种复制的方法都存在一个问题,使用 copy 方法进行复制来演示一下这个问题。

复制代码
>>> a = [[], []]
>>> b = a.copy()
>>> b[0].append(0)
>>> a
[[0], []]

可以发现复制并没有那么彻底,把这种不彻底的复制称之为浅复制。那么,如何不让它进行所谓的浅复制?后面再说,先继续看 dict 的整体复制。

dict 整体复制

假设有一个 dict 的实例 a,要把它复制给 b,能不能直接写 b = a 呢?其实是不行的,不信的话可以看一下下面的示例。

复制代码
>>> a = {'1': 1, '2': 2}
>>> b = a
>>> b['1'] = 0
>>> a
{'1': 0, '2': 2}

可以发现,当 b 修改对应键的值时,a 也跟着修改,因此可以看出 a 和 b 是同一个 dict,如何让 a 和 b 只是值相等,但它们是不同的 dict 呢?

最容易想到的方法就是使用 dict 的方法 copy,还是这个例子。

复制代码
>>> a = {'1': 1, '2': 2}
>>> b = a.copy()
>>> b['1'] = 0
>>> a
{'1': 1, '2': 2}

可以发现修改 b 对 a 没有任何影响,因此完成了复制。

完成复制的操作其核心代码就是第二行,还可以使用下面几种方法来完成复制。

复制代码
>>> b = dict(a)
>>> b = {k: a[k] for k in a}

但是,这几种复制的方法都存在一个问题,使用 copy 方法进行复制来演示一下这个问题。

复制代码
>>> a = {'1': [1], '2': [2]}
>>> b = a.copy()
>>> b['1'].append(1)
>>> a
{'1': [1, 1], '2': [2]}

可以发现这样的复制都是浅复制,如何不进行浅复制呢?答案是进行深复制即可。

深复制

深复制,即同时复制值及其包含的所有值,"深复制是彻底的复制!"

深复制Python 有模块已经实现好了,开箱即用。还是使用上面的例子进行演示。

复制代码
>>> a = {'1': [1], '2': [2]}
>>> from copy import deepcopy
>>> b = deepcopy(a)
>>> b['1'].append(1)
>>> a
{'1': [1], '2': [2]}

同样的,对于 list 套 list 的情况也必须使用深复制。

相关推荐
databook13 小时前
Manim实现闪光轨迹特效
后端·python·动效
Juchecar15 小时前
解惑:NumPy 中 ndarray.ndim 到底是什么?
python
用户83562907805115 小时前
Python 删除 Excel 工作表中的空白行列
后端·python
Json_15 小时前
使用python-fastApi框架开发一个学校宿舍管理系统-前后端分离项目
后端·python·fastapi
数据智能老司机21 小时前
精通 Python 设计模式——分布式系统模式
python·设计模式·架构
数据智能老司机1 天前
精通 Python 设计模式——并发与异步模式
python·设计模式·编程语言
数据智能老司机1 天前
精通 Python 设计模式——测试模式
python·设计模式·架构
数据智能老司机1 天前
精通 Python 设计模式——性能模式
python·设计模式·架构
c8i1 天前
drf初步梳理
python·django
每日AI新事件1 天前
python的异步函数
python