我想了解原因:
a = []
; del a
;和del a[:]
; 表现得如此不同。
我为每个人进行了测试,以说明我目睹的差异:
>>> # Test 1: Reset with a = []
...
>>> a = [1,2,3]
>>> b = a
>>> a = []
>>> a
[]
>>> b
[1, 2, 3]
>>>
>>> # Test 2: Reset with del a
...
>>> a = [1,2,3]
>>> b = a
>>> del a
>>> a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
>>> b
[1, 2, 3]
>>>
>>> # Test 3: Reset with del a[:]
...
>>> a = [1,2,3]
>>> b = a
>>> del a[:]
>>> a
[]
>>> b
[]
我确实找到Different ways of clearing lists,但我没有找到行为差异的解释。任何人都可以澄清这个吗?
答案 0 :(得分:25)
>>> a = [1,2,3] # set a to point to a list [1, 2, 3]
>>> b = a # set b to what a is currently pointing at
>>> a = [] # now you set a to point to an empty list
# Step 1: A --> [1 2 3]
# Step 2: A --> [1 2 3] <-- B
# Step 3: A --> [ ] [1 2 3] <-- B
# at this point a points to a new empty list
# whereas b points to the original list of a
>>> a = [1,2,3] # set a to point to a list [1, 2, 3]
>>> b = a # set b to what a is currently pointing at
>>> del a # delete the reference from a to the list
# Step 1: A --> [1 2 3]
# Step 2: A --> [1 2 3] <-- B
# Step 3: [1 2 3] <-- B
# so a no longer exists because the reference
# was destroyed but b is not affected because
# b still points to the original list
>>> a = [1,2,3] # set a to point to a list [1, 2, 3]
>>> b = a # set b to what a is currently pointing at
>>> del a[:] # delete the contents of the original
# Step 1: A --> [1 2 3]
# Step 2: A --> [1 2 3] <-- B
# Step 2: A --> [ ] <-- B
# both a and b are empty because they were pointing
# to the same list whose elements were just removed
答案 1 :(得分:15)
在您的三种&#34;删除Python列表&#34; 的方法中,只有一个实际上改变了原始列表对象;另外两个只影响名称。
a = []
创建新列表对象,并将其分配给名称a
。del a
删除名称,不它所引用的对象。del a[:]
从名称a
引用的列表中删除所有引用(尽管类似地,它并不直接影响从引用的对象中引用的对象列表)。可能值得阅读关于Python名称和值的this article,以便更好地了解这里发生的事情。
答案 2 :(得分:7)
Test 1:
将a
重新绑定到新对象,b
仍保留引用到原始对象,a
只是一个名称将a
重新绑定到新对象不会更改b
指向的原始对象。
Test 2:
您将名称a
删除,以便它不再存在,但您仍然可以使用b
对内存中的对象进行引用。
Test 3
a[:]
就像复制列表或想要更改列表的所有元素一样,是指对列表中存储的对象的引用,而不是名称a
。 b
也会被清除,因为它是a
的引用,因此对a
内容的更改将影响b
。
行为是documented:
有一种方法可以从给定索引的列表中删除项目 它的价值:
del
声明。这与pop()
不同 返回值的方法。del
语句也可用于 从列表中删除切片或清除整个列表(我们做了 之前通过将一个空列表分配给切片)。例如:>>> >>> a = [-1, 1, 66.25, 333, 333, 1234.5] >>> del a[0] >>> a [1, 66.25, 333, 333, 1234.5] >>> del a[2:4] >>> a [1, 66.25, 1234.5] >>> del a[:] >>> a []
del
也可用于删除整个变量:>>> >>> del a
以后引用名称
a
是一个错误(至少在另一个之前 值被分配给它)。我们稍后会找到del
的其他用途。
因此,只有del a
实际删除a
,a = []
将a重新绑定到新对象,del a[:]
清除a
。在第二次测试中,如果b
没有对该对象的引用,那么它将被垃圾收集。
答案 3 :(得分:5)
del a
正从范围中删除变量a
。引自python docs:
删除名称会删除该名称与本地名称的绑定 全局命名空间,取决于名称是否出现在全局中 同一代码块中的语句。
del a[:]
只是删除a
的内容,因为删除被传递给a
对象,而不是应用于它。再次来自文档:
传递删除属性引用,订阅和切片 涉及的主要对象;通常删除切片 相当于分配一个正确类型的空切片(但是甚至 这是由切片的对象确定的。
。
答案 4 :(得分:3)
在这三种方法中,只有第三种方法实际上会导致删除“&#39; a&#39;指着。让我们快速概述一下。
当你正确a = [1, 2, 3]
时,它会在内存中创建一个列表,其中包含[1,2,3]项,然后获取&#39; a&#39;指向它。当你写b = a
这个预制品时,会发现什么?称为“浅色副本”,#39;即它使&#39; b&#39;指向同一块内存和&#39; a。&#39;深拷贝将涉及将列表的内容复制到新的内存块中,然后指向该内容。
现在,当您撰写a = []
时,您正在创建一个新的列表,其中没有任何项目,并且正在创建一个&#39;指向它。原始列表仍然存在,并且&#39; b&#39;指着它。
在第二种情况下,del a
删除指向[1,2,3]的指针而不删除它自己的数组。这意味着b
仍然可以指向它。
最后,del a[:]
会查看数据&#39; a&#39;指向并清空它的内容。 &#39;一个&#39;仍然存在,所以你可以使用它。 &#39; B&#39;也存在,但它指向同一个空列表&#39; a&#39;是的,这就是它给出相同输出的原因。
答案 5 :(得分:0)
要了解删除列表的不同方法之间的区别,让我们在图片的帮助下逐一查看每个列表。
>>> a1 = [1,2,3]
创建新的列表对象并将其分配给a1
。
>>> a2 = a1
我们将a1
分配给a2
。因此,列表a2
现在指向a1
指向的列表对象。
以下解释的不同方法:
方法-1使用[]
:
>>> a1 = []
在将空列表分配给a1
时,对a2
没有影响。 a2
仍引用相同的列表对象,但a1
现在引用空列表。
方法-2使用del [:]
>>> del a1[:]
这将删除a1
指向的列表对象的所有内容。 a1
现在指向一个空列表。由于a2
也引用了相同的列表对象,因此它也变为空列表。
方法-3使用del a1
>>> del a1
>>> a1
NameError: name 'a1' is not defined
这会从范围中删除变量a1
。这里,只删除变量a1
,原始列表仍然存在于内存中。 a2
仍然指向a1
过去指向的原始列表。如果我们现在尝试访问a1
,我们将获得NameError
。