因为a[:] 只是a 的一个副本,由与a 相同的对象组成,但与a 不同。它们的元素相同,但它们不同。
让我们创建一个列表并做一些id 检查:
a = [1, 2, 3]
print(id(a)) # 97731118088
print(id(a[:])) # 97731213576
print(id(a[:])) # 97731212104
print(id(a[:])) # 97731198600
注意 ids 的副本 a[:] 的变化。它是一个在每次调用时动态创建的对象,最重要的是,即使是a[:] is a[:] 而不是True!让我们看看他们的元素ids 得出一个结论:
print(id(a[0])) # 1648192992
print(id(a[:][0])) # 1648192992
a[0] is a[:][0] # True
a[1] is a[:][1] # True
a[2] is a[:][2] # True
因此,我们可以得出结论,a[:] 是一个由a 的元素组成的对象,但与a 不同,并且每次调用它时都是不同的对象。 a 和 a[:] 的元素都是相同的,但它们本身并不相同。
所以del a[:] 所做的就是删除所有的元素 a。这样a 就发生了变异,你最终会得到一个空的a,即[]。但是,del a 将名称 a 从命名空间中完全删除,当您要求 Python 为您打印 a 时,您将得到一个 NameError: name 'a' is not defined。
但是我们怎么知道呢?好吧,让我们通过在a 和a[:] 上拆解del 来获得一些观点:
让我们定义两个函数:
def deletion1(a):
del a
def deletion2(a):
del a[:]
让我们分解它们:
import dis
dis.dis(x = deletion1)
1 0 DELETE_FAST 0 (a)
2 LOAD_CONST 0 (None)
4 RETURN_VALUE
dis.dis(x = deletion2)
1 0 LOAD_FAST 0 (a)
2 LOAD_CONST 0 (None)
4 LOAD_CONST 0 (None)
6 BUILD_SLICE 2
8 DELETE_SUBSCR
10 LOAD_CONST 0 (None)
12 RETURN_VALUE
dis documentation 表示第一个函数所做的DELETE_FAST 操作只是“删除本地co_varnames[var_num]”。这基本上是删除该名称 a 以便您无法再访问列表对象。请注意,这不会删除由名称 a 引用的对象,而只是删除其名称,以便 a 不再是对任何内容的引用。对象97731118088还是同一个列表,[1, 2, 3]:
import gc
for obj in gc.get_objects():
if id(obj) == 97731118088:
print(obj)
# [1, 2, 3]
另一方面,同样来自文档DELETE_SUBSCR“实现del TOS1[TOS]”,它基本上是“移除堆栈顶部并将结果推回堆栈的就地运算符”。这样一来,堆栈元素被删除,剩下的名称为a,它现在指的是一个元素被删除的列表,即只是一个“空壳”,如果你愿意的话。执行此操作后,a 变为 [],但仍具有与 97731118088 相同的 id。只是其元素通过就地删除而消失了。