【问题标题】:What is the difference between slice assignment that slices the whole list and direct assignment?切片整个列表的切片赋值和直接赋值有什么区别?
【发布时间】:2012-04-26 17:02:38
【问题描述】:

我在很多地方看到lists 使用切片分配。当与(非默认)索引一起使用时,我能够理解它的用途,但我无法理解它的用途,例如:

a_list[:] = ['foo', 'bar']

这和它有什么不同

a_list = ['foo', 'bar']

?

【问题讨论】:

    标签: python list variable-assignment slice


    【解决方案1】:
    a_list = ['foo', 'bar']
    

    在内存中创建一个新的list 并将名称a_list 指向它。 a_list之前所指的无关紧要。

    a_list[:] = ['foo', 'bar']
    

    调用a_list 对象的__setitem__ 方法,以slice 作为索引,在内存中创建一个新的list 作为值。

    __setitem__ 评估slice 以找出它代表的索引,并在它传递的值上调用iter。然后它遍历对象,将slice 指定范围内的每个索引设置为对象的下一个值。对于lists,如果slice 指定的范围与可迭代的长度不同,则调整list 的大小。这使您可以做许多有趣的事情,例如删除列表的各个部分:

    a_list[:] = [] # deletes all the items in the list, equivalent to 'del a_list[:]'
    

    或在列表中间插入新值:

    a_list[1:1] = [1, 2, 3] # inserts the new values at index 1 in the list
    

    但是,对于“扩展切片”,step 不是一个,迭代必须是正确的长度:

    >>> lst = [1, 2, 3]
    >>> lst[::2] = []
    Traceback (most recent call last):
      File "<interactive input>", line 1, in <module>
    ValueError: attempt to assign sequence of size 0 to extended slice of size 2
    

    将切片分配给a_list 的主要不同之处在于:

    1. a_list 必须已经指向一个对象
    2. 该对象已被修改,而不是将 a_list 指向新对象
    3. 该对象必须支持带有slice 索引的__setitem__
    4. 右边的对象必须支持迭代
    5. 没有名称指向右侧的对象。如果没有其他对它的引用(例如当它是您的示例中的文字时),它将在迭代完成后被计数为不存在。

    【讨论】:

    • 我在文档中读到了这个(docs.python.org/tutorial/introduction.html#lists)。只是默认索引是我的疑问:)
    • "对于列表,如果切片指定的范围与可迭代的长度不同,则调整列表的大小。"仅当范围的步长值为 1 时才适用。对于 1 以外的步长值,分配的可迭代对象必须产生正确的项目数。
    • @SvenMarnach 谢谢。我在最后加上了这一点,因为我忘了提到它,而且我知道在某些情况下它必须是相同的长度。
    【解决方案2】:

    差别很大!在

    a_list[:] = ['foo', 'bar']
    

    您修改了绑定到名称 a_list 的现有列表。另一方面,

    a_list = ['foo', 'bar']
    

    为名称a_list分配一个新列表。

    也许这会有所帮助:

    a = a_list = ['foo', 'bar'] # another name for the same list
    a_list = ['x', 'y'] # reassigns the name a_list
    print a # still the original list
    
    a = a_list = ['foo', 'bar']
    a_list[:] = ['x', 'y'] # changes the existing list bound to a
    print a # a changed too since you changed the object
    

    【讨论】:

      【解决方案3】:

      通过分配给a_list[:]a_list 仍然引用相同的列表对象,但内容已修改。通过分配给a_lista_list 现在引用一个新的列表对象。

      查看它的id

      >>> a_list = []
      >>> id(a_list)
      32092040
      >>> a_list[:] = ['foo', 'bar']
      >>> id(a_list)
      32092040
      >>> a_list = ['foo', 'bar']
      >>> id(a_list)
      35465096
      

      如您所见,它的id 不会随切片分配版本而改变。


      两者之间的差异可能会导致完全不同的结果,例如,当列表是函数的参数时:

      def foo(a_list):
          a_list[:] = ['foo', 'bar']
      
      a = ['original']
      foo(a)
      print(a)
      

      这样,a 也被修改了,但如果使用 a_list = ['foo', 'bar'] 代替,a 保持其原始值。

      【讨论】:

        【解决方案4】:
        a_list = ['foo', 'bar']
        a=a_list[:]  # by this you get an exact copy of a_list 
        print(a)
        a=[1,2,3] # even if you modify a it will not affect a_list
        print(a)
        print(a_list)
        

        【讨论】:

        • 问题是关于将['foo', 'bar'] 分配给a_list[:]
        猜你喜欢
        • 2021-01-15
        • 1970-01-01
        • 2011-03-23
        • 2021-04-14
        • 2020-08-10
        • 1970-01-01
        • 2013-04-23
        • 2016-10-19
        相关资源
        最近更新 更多