不同的方式删除列表
我想明白为什么:
-
a = []
; -
del a
; 和 -
del a[:]
;
performance如此不同。
我对每个人都进行了testing,以说明我所见证的差异:
>>> # 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 []
我的确发现了清单清单的不同方式 ,但我没有find对行为差异的解释。 任何人都可以澄清这一点?
testing1
>>> 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
testing2
>>> 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
testing3
>>> 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
在你的三种“删除Python列表”的方法中 , 只有一个实际上改变了原来的列表对象; 另外两个只影响名字 。
-
a = []
创build一个新的列表对象 ,并将其分配给名称a
。 - 删除名称 , 而不是它引用的对象。
-
del a[:]
删除名称a
引用的列表中的所有引用 (尽pipe同样,它不会直接影响从列表中引用的对象)。
可能值得阅读这篇关于Python名字和值的文章 ,以更好地理解这里发生了什么。
Test 1:
重新绑定a
新对象, b
仍然保存对原始对象的引用 , a
只是通过重新绑定到一个新对象的名称不会更改b
指向的原始对象。
Test 2:
你删除了名字a
所以它不再存在,但是你仍然有一个对b
的对象的引用。
Test 3
a[:]
就像当你复制一个列表或者想要改变一个列表的所有元素一样,引用的是存储在列表中的对象而不是名字a
。 b
也被清除,因为它又是一个对a
意志效应b
的内容的改变。
行为被logging :
有一种方法可以从列表中删除一个项目给它的索引,而不是它的值:
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
也可以用来删除整个variables:>>> >>> del a
以后引用这个名字是一个错误(至less直到另外一个值被分配给它)。 之后我们会发现
del
其他用途。
所以只有del a
实际上删除a
, a = []
将a重新绑定到一个新的对象, del a[:]
清除a
。 在你的第二个testing中,如果b
没有引用该对象,它将被垃圾收集。
del a
从范围中删除variablesa
。 从python文档引用:
删除名称将删除该名称与本地或全局名称空间的绑定,具体取决于名称是否出现在同一代码块中的全局语句中。
del a[:]
只是删除一个的内容,因为删除被传递给a
对象,而不是应用到它。 再次从文档:
属性引用,订阅和切片的删除被传递给涉及的主对象; 删除切片通常相当于分配了正确types的空片(即使这是由切片对象决定的)。
。
在这三种方法中,只有第三种方法实际上导致删除“a”指向的列表。 让我们做一个快速的概述。
当你正确的a = [1, 2, 3]
它会在内存中创build一个列表,其中的项目[1,2,3]然后得到'a'指向它。 当你写b = a
这会形成什么叫做“浅拷贝”,也就是说,“b”指向与“a”相同的内存块。 深度复制将涉及将列表的内容复制到新的内存块中,然后指向该内存块。
现在,当你写a = []
你正在创build一个没有任何项目的新列表,并得到'a'指向它。 原始列表仍然存在,'b'指向它。
在第二种情况下, del a
删除指向[1,2,3]的指针而不是它自己的数组。 这意味着b
仍然可以指向它。
最后, del a[:]
通过数据“a”指向并清空它的内容。 “a”依然存在,所以你可以使用它。 'b'也存在,但它指向同一个空列表'a',这就是为什么它给出相同的输出。
要理解删除列表的不同方式之间的区别,让我们逐一在图片的帮助下看到它们。
>>> a1 = [1,2,3]
新的列表对象被创build并被分配给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
这将从作用域中删除variablesa1
。 在这里,只是variablesa1
被删除,原始列表仍然存在于内存中。 a2
仍指向a1
用来指向的原始列表。 如果我们现在尝试访问a1
,我们将得到一个NameError
。