a[:] = b和a = b[:]有什么区别?(Python)

8 投票
3 回答
1221 浏览
提问于 2025-04-16 23:25

我在一次编程测试中被问到这个问题,但我不知道答案。有没有人能给点建议?

3 个回答

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

这三种列表打印出来的结果是一样的。列表 ca 共享同一个对象,所以当 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[:] = b 可能会比 a = b[:] 稍微快一点。因为第一种方式不需要创建一个新的列表对象,它只需修改已有的列表。这样做的一个好处是可以重用已经占用的内存,而不是重新分配新的内存。

3

a = b[:] 这行代码会调用 b__getslice____getitem__ 方法,然后把结果赋值给 a。在绝大多数情况下(比如列表、元组和其他序列类型),这会创建一个“浅拷贝”,也就是说,a 会得到 b 的一个副本。我不知道有没有不这样做的类,但可能会有用户自定义的类型会有不同的表现。之前指向 a 的其他对象,仍然会指向旧的值。

a[:] = b 则是调用 __setslice____setitem__ 方法,用 b 的元素替换 a 中的一部分元素。在这种情况下,如果 a 的序列类型表现正常,这将会替换掉整个 a,因为 : 这个范围没有指定起止点,表示整个序列。这里的区别在于,不可变类型,比如元组,是不允许执行 __setslice__ 的(例如会抛出 TypeError 异常)。之前指向 a 的其他对象也会被更新,因为底层对象正在被修改。

对于可变类型,比如 lista = b[:] 的结果和 a[:] = b 是一样的,a 会是 b 的一个浅拷贝;而对于不可变类型,比如 tuplea[:] = b 是无效的。对于表现不佳的用户自定义类型,情况就不一定了。还有一个区别是,之前指向同一个对象的其他对象会有什么变化——使用 a = b[:] 时,它们指向的是原始值(a),而使用 a[:] = b 时,它们指向的是被修改后的对象(b 的浅拷贝)。

10

[:] 是一个切片操作符。

当它出现在左边时,它会直接替换列表里的内容,而不会新建一个列表的引用。

当它出现在右边时,它会复制一个和原列表内容相同的新列表。

撰写回答