a[:] = b 和 a = b[:] 之间的区别是什么?(Python)

8

我在一次编码测试中被问到这个问题,但不知道答案。有人有任何想法吗?


可能是Python中列表和列表[:]之间的区别是什么?的重复问题。 - Ignacio Vazquez-Abrams
1
@Ignacio:不,这不是重复的问题--那个问题没有提到a[:] = b结构。 - Adam Rosenfield
@Adam:甚至包括“当分配时…”这部分吗? - Ignacio Vazquez-Abrams
3个回答

10

[:] 是 Python 中的切片操作符。

将其放在列表左侧时,可以直接修改列表中的内容而不创建新的引用。

将其放在列表右侧时,可以创建一个包含相同内容的列表副本。


哦,现在明白了。为了澄清,当执行a[:] = b时,id(a)不会改变。只有当执行a = b[:]时,id(a)才会改变。是否有一种方法比另一种更好呢? - user701632
是的,你说得对。如果“c”也指向与“a”相同的列表,则可能需要更改内容,以便两个变量都指向更新后的列表。 - recursive

3

a = b[:] 调用 __getslice____getitem__b 上,并将结果赋值给 a。在几乎所有情况下(例如列表、元组和其他序列类型),这会生成一个浅拷贝;我不知道有哪些类没有实现这种行为,但你可能有一个用户定义的类型,它会执行不同的操作。任何先前引用旧值 a 的其他对象将继续引用该旧值。

另一方面,a[:] = b 调用 __setslice____setitem__ 来替换 a 的子集合为序列 b 中的元素。在这种情况下,如果 a 的序列类型是良好的,由于没有端点的范围 : 表示整个序列,因此将替换 a 的全部内容。不同之处在于,不可变类型(例如元组)将不允许你执行 __setslice__(例如通过抛出 TypeError 异常)。任何先前引用 a 的其他对象也将被更新,因为正在修改底层对象。

对于可变类型(例如 list),a = b[:] 的结果与 a[:] = b 相同,因为 a 将是 b 的浅拷贝;对于不可变类型(例如 tuple),a[:] = b 是无效的。对于行为不良的用户定义类型,则情况未知。还有一个区别是其他引用相同对象的对象 -- 通过 a = b[:],它们引用原始值(a),但通过 a[:] = b,它们引用修改后的对象(b 的浅拷贝)。


2
在这两种情况下,列表a最终都会成为列表b的副本。但是实现此目的所使用的方法已经改变。 a[:] = b修改列表a,使其具有与b相同的元素。 a = b[:]生成一个新列表,该列表是b的副本并替换列表a
区别在于我们是否修改了现有列表或创建了一个新列表。
要查看差异,请执行以下操作:
a = range(3)
b = range(4)
c = a # c and a now share the same list
a[:] = b
print "a", a
print "b", b
print "C", c

所有三个列表都将输出相同的结果。C 和 a 共享同一对象,所以当修改 a 时,c 也会被修改。
a = range(3)
b = range(4)
c = a # c and a now share the same list
a = b[:]
print "a", a
print "b", b
print "C", c

现在c不会再和a打印出相同的结果了。赋值后,ac不再共享同一个对象。

就速度而言,a[:] = ba = b[:]稍快一些。前者不需要创建新的列表对象,它只需修改现有列表即可。其中很大一部分原因是它可以重用已经拥有的列表内存,而不是分配新的内存。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接