• 2020-2-10 Python 列表切片陷阱:引用、复制与深复制


    Python 列表的切片和赋值操作很基础,之前也遇到过一些坑,以为自己很懂了。但今天刷 Codewars 时发现了一个更大的坑,故在此记录。

    Python 列表赋值:复制“值”还是“引用”?

    很多入门 Python 的人会犯这样一个错误:在赋值操作=中搞不清是赋了“值”还是“引用”。比如:

    1. a = [1, 2, 3]
    2. b = a
    3. b[0] = 10 # 更改列表 b 的第一个元素,但 a 现在也被更改为了 [10, 2, 3]

    他可能只想改变列表b,但实际上这样也会改变列表a

    因为b实际上是列表a的另一个引用ab是同一个对象,id(a) == id(b),所以更改b也会更改a。这个应该大部分人都知道。所以正确的代码应该使用切片来进行列表的复制

    1. a = [1, 2, 3]
    2. b = a[:] # 使用切片进行列表复制
    3. b[0] = 10 # 此时 a 和 b 是两个不同的对象

    二维列表引发的思考:列表的本质

    好的,现在我们确定切片能够进行列表的复制。那我们就能心安理得地改动新的列表了吗?请看二维列表(二维数组):

    1. a = [[1, 2, 3], [4, 5, 6]]
    2. b = a[:]
    3. b[0][0] = 10

    此时,a还是被改动了!

    原因是,虽然id(a) == id(b)Falseab确实不是同一个对象。但它们的元素都是同一个对象——id(a[0]) == id(b[0])id(a[1]) == id(b[1])。因为列表里存储的是对象的引用!

    列表 list 终究只是个容器。就像 tuple 本身是 immutable (不可变)的,但它只是容器,它可以存储一个可变对象,因此呈现出一种可以被改动的“假象”。例如:

    1. >>> a = ([1],)
    2. >>> a[0][0] = 2
    3. >>> a
    4. ([2],)

    所以容器和它存储的对象不能混为一谈。所以对于这种二维列表,想要进行完全的复制,请直接使用copy.deepcopy()深度复制。

    如果只想复制一部分(切片),那可以先复制再切片:

    1. >>> import copy
    2. >>> a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
    3. >>> b = copy.deepcopy(a)[1:]
    4. >>> b[0][0] = 100
    5. >>> a
    6. [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
    7. >>> b
    8. [[100, 5, 6], [7, 8, 9]]

    此时修改b没有影响到a

    原文链接:http://www.cnblogs.com/gscnblog/p/10372539.html

  • 相关阅读:
    Grid 拾遗
    WPF 依赖属性
    升级cordova
    oracle比较一行的最大值或最小值
    nginx完全关闭log
    hive计算周一的日期
    查看linux文件目录的大小和文件夹包含的文件数
    linux设置服务器时间同步
    oracle取出多个字段列中的最大值和最小值
    oracle SQL语句取本周本月本年的数据
  • 原文地址:https://www.cnblogs.com/reclusive/p/12292251.html
Copyright © 2020-2023  润新知