为什么b [:] = a突变列表b?

时间:2020-01-15 09:37:48

标签: python python-3.x list slice

假设我们有一个列表a=[1,2,3],我需要将a的元素复制到新列表b

我们可以做a=b,但是ab都指向同一列表。因此,对它们中的任何一个进行更改都会对两个列表都进行更改。

>>> a=b
>>> a
[1, 2, 3]
>>> b
[1, 2, 3]
>>> b.append(4)
>>> a,b
([1, 2, 3, 4], [1, 2, 3, 4])
>>> a.append(5)
>>> a,b
([1, 2, 3, 4, 5], [1, 2, 3, 4, 5])
>>> a is b
True
>>> id(a),id(b)
(2287659980360, 2287659980360)

为避免这种情况,我们可以进行b=a[:]a[:]创建一个具有相同值a的不同列表。现在,即使我突变了ab也不会受到影响,反之亦然。 bb[:]是两个不同的列表。

>>> b=a[:]
>>> a,b
([1, 2, 3, 4, 5], [1, 2, 3, 4, 5])
>>> a.append(6)
>>> a,b
([1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5])
>>> b.append(6)
>>> a,b
([1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6])
>>> a is b
False
>>> id(a),id(b)
(2287659980360, 2287653308552)

现在,如果我b[:]=a进行了操作,则我的列表b被突变了。但是b[:]是另一个列表吗? bb[:]都指向不同的列表,对吗?如我错了请纠正我。如果我突变b,为什么b[:]被更改。我想念什么?

>>> a=['a','b','c']
>>> b[:]=a
>>> a,b
(['a', 'b', 'c'], ['a', 'b', 'c'])
>>> id(b),id(b[:])
(2287653308552, 2287660267080)
>>> b is b[:]
False

1 个答案:

答案 0 :(得分:7)

切片用作表达式或分配目标时,意味着不同的事情。

作为表达式,求值b[:]会生成一个新列表。但是,作为分配目标,分配给b[:]并不意味着“求出表达式b[:]然后分配给结果列表”。无论如何,您都无法分配给Python对象。

作为分配目标,分配给b[:]告诉现有列表将其内容替换为要分配给b[:]的任何元素。这是由__setitem__方法处理的,例如b.__setitem__(slice(None, None), a)。没有新的列表产生,并且b[:]未被评估为表达式。

您可以在language reference documentation中的“如果目标是切片”下的分配语句中看到这一点(尽管切片分配的某些约束并不像文档中所描述的那样严格;例如,文档说序列类型需要匹配,但对于大多数类型,它们不需要匹配。