代码之家  ›  专栏  ›  技术社区  ›  Wojciech Morawiec

覆盖列表切片中的值

  •  2
  • Wojciech Morawiec  · 技术社区  · 6 年前

    在更改列表(按索引)切片的值时,我遇到了以下意外行为:

    # Expected behavior:
    >>> a = [1,2,3,4]
    >>> a
    [1, 2, 3, 4]
    >>> a[2] = 5
    >>> a
    [1, 2, 5, 4]
    >>> a[2:]
    [5, 4]
    >>> a[2:] = ['y', 2]
    >>> a
    [1, 2, 'y', 2]
    >>> a[1:]
    [2, 'y', 2]
    >>> a[1:][0]
    2
    # Unexpected behavior:
    >>> a[1:][0] = 'hello'
    >>> a
    [1, 2, 'y', 2] # I would have expected [1, 'hello', 'y', 2] here
    

    如您所见,您可以通过将列表指定给切片来覆盖原始列表,如中所示 a[2:] = ['y', 2] . 但是,如果您试图通过索引(或切片构造的切片)覆盖切片的元素,如 >>> a[1:][:1] = [2] ),没有错误,但是原始列表不会更新。

    1 回复  |  直到 6 年前
        1
  •  3
  •   Shai Avr    6 年前

    在对列表进行切片时,实际上创建了列表的副本(切片的部分),这样它们就不会相互影响:

    x = [1, 2, 3, 4]
    y = x[1:]  # y = [2, 3, 4]
    
    y[0] = "hi"  # y = ["hi", 3, 4]
    # y is a copy of x, so any changes made to y aren't reflected in x
    
    print(x)  # [1, 2, 3, 4]
    

    索引赋值运算符可以使用一个索引(即 x[i] = something start:stop:step ,即 x[1:5] = [1, 2, 3, 4]

    x[1:][0] = "hi"  # x is unchanged
    # x[1:] is a copy of x, so changes to it (like setting the first element to "hi")
    # does nothing useful
    

    相反,您可以自己计算索引或范围:

    # instead of:
    x[start:][1] = "hi"
    # use:
    x[start + 1] = "hi"
    
        2
  •  2
  •   Rob Streeting David Hoerster    6 年前

    发生这种情况的原因是因为切片 a[1:] 是一份与原件完全不同的清单 a . 虽然这只是一个 shallow copy

    a[2:] = ['y', 2] ,其中原始列表实际上被修改,这是因为该语法引用了一种称为 slice assignment ,它确实将原始列表的内容替换为作业右侧的列表。如果进一步对赋值左侧的切片进行子索引,则不会触发此行为。