• Python札记 -- 切片赋值


    一、疑惑
        今天在看《Python Cookbook》第四章Python技巧的4.7小节时,发现一段初看起来让人疑惑的代码。该小节的任务是将一个包含列表(行)的列表,转换成一个新的列表。新的列表包含了同样的行,但是其中一些列被删除或者重新排序了。让人疑惑的代码如下:

    1 listOfRows = [[1,2,3,4], [5,6,7,8], [9,10,11,12]]
    2 listOfRows[:] = [[row[0], row[3], row[2]] for row in listOfRows]

    竹风不禁疑惑了,这第二行的代码为啥会用 "listOfRows[:] =" 这种写法?直接写成 "listOfRows =" 不行么?这两者间有什么区别呢?

    二、线索
        疑惑主要集中在对切片进行赋值上。抱着“实践是检验真理的唯一标准”,竹风做了个小实验:

     1 >>> test_li = ['a','b','c','d','e','f']    #进行测试的list
     2 >>> test_li[1:4]    #简单的切片操作
     3 ['b', 'c', 'd']
     4 >>> id(test_li)    #观察一下测试list的id
     5 139718916544776
     6 >>> test_li[1:4] = [1,2]    #对切片进行赋值,而且是不对等的赋值
     7 >>> test_li    #观察赋值后的list
     8 ['a', 1, 2, 'e', 'f']
     9 >>> id(test_li)    #id没有变化,说明是在原对象上进行修改
    10 139718916544776
    11 >>>

    配合注释来看的话,对切片赋值貌似是在原对象上进行修改。而且值得注意的是,切片赋值还支持元素个数不相等的操作,比如实验中用[1,2]替换了['b','c','d']

    三、真相
        那么真相是什么呢,让我们继续实践一下:

     1 >>> listOfRows = [[1,2,3,4], [5,6,7,8], [9,10,11,12]]
     2 >>>
     3 >>> li = listOfRows
     4 >>> id(listOfRows)
     5 139718916543336
     6 >>> id(li)    #两者的id相同,说明引用了同一个对象
     7 139718916543336
     8 >>> listOfRows = [[row[0], row[3], row[2]] for row in listOfRows]
     9 >>> listOfRows    #使用列表推导产生的结果符合预期
    10 [[1, 4, 3], [5, 8, 7], [9, 12, 11]]
    11 >>> li    #li没有改变
    12 [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
    13 >>> id(listOfRows)
    14 139718916544416
    15 >>> id(li)    #两者id不同,说明listOfRows绑定了一个新的对象
    16 139718916543336
    17 >>>

    直接使用 "listOfRows =" 的话,产生了一个新的对象,让我们继续看看 "listOfRows[:] =" 的效果:

     1 >>> listOfRows = [[1,2,3,4], [5,6,7,8], [9,10,11,12]]
     2 >>> 
     3 >>> li = listOfRows
     4 >>> id(listOfRows)
     5 140034137774560
     6 >>> id(li)    #两者id一致,引用了同一个对象
     7 140034137774560
     8 >>> listOfRows[:] = [[row[0], row[3], row[2]] for row in listOfRows]
     9 >>> listOfRows    #使用切片赋值,达到预期效果
    10 [[1, 4, 3], [5, 8, 7], [9, 12, 11]]
    11 >>> li    #li也发生了变化,因为两者绑定的是同一个对象
    12 [[1, 4, 3], [5, 8, 7], [9, 12, 11]]
    13 >>> id(listOfRows)
    14 140034137774560
    15 >>> id(li)    #两者的id都没有变化,说明切片赋值实在原对象上修改
    16 140034137774560
    17 >>>

        最后的结束语了:列表推导会产生一个新的列表,而不是修改现有的列表。如果需要一个新的对象,那么可以使用 "listOfRows ="  写法。当需要修改一个现有的列表时,最好的办法是将现有列表的内容赋值为一个列表推导,也就是使用"listOfRows[:] =" 写法。简单地说,使用切片赋值可以修改原对象的类容,而不是创建一个新对象。谢谢大家~~

  • 相关阅读:
    NOIP2018游记
    NOIP2018T1DAY1——Road(并查集做法??)
    UVA11021 Tribles——概率dp
    捡石头——(期望递推)
    USACO2008mar-gold牛跑步(第k短路:A-star)
    Java中的异常处理
    Java学习手册
    各种应用层注入手段整理 【转载】
    正则表达式学习
    Run-Time Check Failure #0,The value of ESP was not properly saved 错误解决
  • 原文地址:https://www.cnblogs.com/PandaBamboo/p/3261646.html
Copyright © 2020-2023  润新知