删除列表的不同方法

Different ways of deleting lists

我想了解原因:

行为如此不同。

我 运行 对每个进行测试以说明我所看到的差异:

>>> # 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,但我没有找到对行为差异的解释。谁能澄清一下?

Test 1:a 重新绑定到新对象,b 仍然持有对原始对象的 引用 a只是通过将 a 重新绑定到新对象的名称不会更改 b 指向的原始对象。

Test 2: 你删除了名称 a 所以它不再存在但是你仍然有一个对内存中对象的引用 b.

Test 3 a[:] 就像当您复制列表或想要更改列表的所有元素时,指的是对存储在列表中的对象的引用而不是名称 a . b 也被清除,因为它是对 a 的引用,因此对 a 内容的更改将影响 b.

行为是 documented:

There is a way to remove an item from a list given its index instead of its value: the del statement. This differs from the pop() method which returns a value. The del statement can also be used to remove slices from a list or clear the entire list (which we did earlier by assignment of an empty list to the slice). For example:

>>>
>>> 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 can also be used to delete entire variables:

>>>
>>> del a

Referencing the name a hereafter is an error (at least until another value is assigned to it). We'll find other uses for del later.

所以只有 del a 实际删除 aa = [] 将 a 重新绑定到新对象,del a[:] 清除 a。在你的第二个测试中,如果 b 没有保存对对象的引用,它将被垃圾收集。

del a

正在从范围中删除变量 a。引用自 python docs:

Deletion of a name removes the binding of that name from the local or global namespace, depending on whether the name occurs in a global statement in the same code block.

del a[:]

只是删除 a 的内容,因为删除是传递给 a 对象,而不是应用于它。再次来自文档:

Deletion of attribute references, subscriptions and slicings is passed to the primary object involved; deletion of a slicing is in general equivalent to assignment of an empty slice of the right type (but even this is determined by the sliced object).

测试 1

>>> 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

测试 2

>>> 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

测试 3

>>> 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  

在你的三个 "ways of deleting Python lists" 中,只有一个 实际上改变了原始列表对象;另外两个只影响名字

  1. a = [] 创建一个 新列表对象 ,并将其分配给名称 a.
  2. del a 删除名称不是它所指的对象。
  3. del a[:] 从名称 a 引用的列表中删除 所有引用 (尽管类似地,它不直接影响被引用的对象从列表中引用)。

可能值得阅读 this article 关于 Python 名称和值的内容,以便更好地理解这里发生的事情。

在这三种方法中,只有第三种方法实际导致删除 'a' 指向的列表。让我们快速概览一下。

当您右 a = [1, 2, 3] 时,它会在内存中创建一个列表,其中包含项目 [1, 2, 3],然后让 'a' 指向它。当你写 b = a 时,这预制了所谓的 'shallow copy,' 即它使 'b' 指向与 'a.' 相同的内存块,深度复制将涉及复制内容list 到一个新的内存块,然后指向那个。

现在,当您编写 a = [] 时,您正在创建一个没有任何项目的新列表,并让 'a' 指向它。原始列表仍然存在,'b' 指向它。

在第二种情况下,del a 删除指向 [1,2,3] 的指针,而不是数组本身。这意味着 b 仍然可以指向它。

最后,del a[:] 遍历 'a' 指向的数据并清空其中的内容。 'a' 仍然存在,所以你可以使用它。 'b' 也存在,但它指向相同的空列表 'a',这就是为什么它给出相同的输出。

要了解不同删除列表方式的区别,让我们借助图片一一了解。

>>> a1 = [1,2,3]

一个新的列表对象被创建并分配给 a1

>>> a2 = a1

我们将 a1 分配给 a2。因此,list a2 现在指向 a1 指向的列表对象。

下面解释的不同方法:

方法一使用[]

>>> 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.