• 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
    []
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    由此可以得出,创建 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]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

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

    >>> a = [[]] * 10
    >>> a
    [[], [], [], [], [], [], [], [], [], []]
    >>> a[0].append(0)
    >>> a
    [[0], [0], [0], [0], [0], [0], [0], [0], [0], [0]]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

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

    >>> a = [[] for _ in range(10)]
    >>> a
    [[], [], [], [], [], [], [], [], [], []]
    >>> a[0].append(0)
    >>> a
    [[0], [], [], [], [], [], [], [], [], []]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

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

    整体复制

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

    list 整体复制

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

    >>> a = [1, 2, 1]
    >>> b = a
    >>> b[2] = 3
    >>> a
    [1, 2, 3]
    
    • 1
    • 2
    • 3
    • 4
    • 5

    可以发现,修改 b 的时候,a 也跟着改了,可以看出 a 和 b 是同一个 list,如何让 a 和 b 只是值相等,但它们是不同的 list 呢?
    最容易想到的方法就是使用 list 的方法 copy,还是这个例子。

    >>> a = [1, 2, 1]
    >>> b = a.copy()
    >>> b[2] = 3
    >>> a
    [1, 2, 1]
    
    • 1
    • 2
    • 3
    • 4
    • 5

    可以发现修改 b 对 a 没有任何影响,因此完成了复制。
    完成复制的操作其核心代码就是第二行,还可以使用下面几种方法来完成复制。

    >>> b = a[:]
    >>> b = list(a)
    >>> b = [_ for _ in a]
    >>> b = a + []  # 写成 b = [] + a 也可以
    >>> b = a * 1  # 写成 b = 1 * a 也可以
    
    • 1
    • 2
    • 3
    • 4
    • 5

    其中后面两种可能不是那么容易能够想得到的,这些方法都能完成复制,可以自己进行验证。
    但是,这几种复制的方法都存在一个问题,使用 copy 方法进行复制来演示一下这个问题。

    >>> a = [[], []]
    >>> b = a.copy()
    >>> b[0].append(0)
    >>> a
    [[0], []]
    
    • 1
    • 2
    • 3
    • 4
    • 5

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

    dict 整体复制

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

    >>> a = {'1': 1, '2': 2}
    >>> b = a
    >>> b['1'] = 0
    >>> a
    {'1': 0, '2': 2}
    
    • 1
    • 2
    • 3
    • 4
    • 5

    可以发现,当 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}
    
    • 1
    • 2
    • 3
    • 4
    • 5

    可以发现修改 b 对 a 没有任何影响,因此完成了复制。
    完成复制的操作其核心代码就是第二行,还可以使用下面几种方法来完成复制。

    >>> b = dict(a)
    >>> b = {k: a[k] for k in a}
    
    • 1
    • 2

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

    >>> a = {'1': [1], '2': [2]}
    >>> b = a.copy()
    >>> b['1'].append(1)
    >>> a
    {'1': [1, 1], '2': [2]}
    
    • 1
    • 2
    • 3
    • 4
    • 5

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

    深复制

    深复制,即同时复制值及其包含的所有值,“深复制是彻底的复制!”
    深复制Python 有模块已经实现好了,开箱即用。还是使用上面的例子进行演示。

    >>> a = {'1': [1], '2': [2]}
    >>> from copy import deepcopy
    >>> b = deepcopy(a)
    >>> b['1'].append(1)
    >>> a
    {'1': [1], '2': [2]}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

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

  • 相关阅读:
    成都榆熙电子商务有限公司:沉默店铺还可以做起来吗?怎么做?
    SpringBoot监听redis Key变化事件详解
    护眼灯真的可以护眼吗?2022护眼台灯该怎样选择
    ORA-01558故障恢复----惜分飞
    windows11安装SQL server报错等待数据库引擎恢复句柄失败
    Windows常用快捷键与查询命令
    OneFlow v0.6.0正式发布
    IDM统一身份平台策略配置说明
    centos7最简洁的搭建samba服务器
    缓存穿透、缓存击穿、缓存雪崩以及解决方法
  • 原文地址:https://blog.csdn.net/a1137588003/article/details/133045105