list.pop()和list = list[:-1]的区别

6
>>> a = [1,2,3]
>>> a.pop()
3
>>> a
[1, 2]
>>> a = [1,2,3]
>>> a = a[:-1]
>>> a
[1, 2]
>>>

以上方法从列表中删除最后一个元素之间有什么区别吗?


2
是的,使用 pop 在常数时间内就地修改了被 a 引用的列表,而使用切片则创建了一个新列表并将其分配给 a,并在线性时间内工作。 - juanpa.arrivillaga
6个回答

20
是的。pop 的时间复杂度为 O(1),并且会改变原始列表,而切片的时间复杂度为 O(n),并且会创建一个列表的副本。更不正式地说,pop 方法是对列表末尾元素的操作,并在 CPython 中定义为调用 list_resize(self, Py_SIZE(self) - 1);。 这不需要遍历整个结构。
另一方面,list_slice 会分配一个新的列表,并循环遍历旧列表中的条目,范围从开头到结尾-1,将每个项目的引用复制到新列表中。
如果你想要做的是删除列表的最后一个元素,请使用 popdel a[-1]

1
pop 可以接受一个索引参数,例如 pop(0),在这种情况下,它仍然是 O(1) 吗? - LiuXiMin
5
好问题。不,pop在栈数据结构的“顶部”或“后部/右侧”传统上是O(1)操作。Python中的列表给pop增加了一个额外参数以使其能够在中间工作,但是列表中的其他元素需要向前移动以填补空缺,这是O(n)。查看源代码以获取完整的故事。有一个条件语句在pop()pop(n)之间进行切换——后者调用list_ass_slice(self, index, index+1, (PyObject *)NULL);对列表执行向前移动操作。如果您经常使用pop(0),请查看collections.deque - ggorlen
实际上,如果你只想删除list的最后一个元素,那么使用del mylist[-1]就可以了。当你想要删除list的最后一个元素并保留该值(pop返回该值)时,你会使用popdel mylist[-1]pop具有相同的大O行为,并且它直接支持语法/字节码,这通常比函数调用更快(尽管现代版本的CPython通过加速简单方法调用来缩小差距)。 - ShadowRanger

3

pop不改变列表的标识符,只是从列表中弹出一个项目。

[:-1]是切片操作,它从旧列表创建一个新列表。

>>> a = [1,2,3]
print(id(a))
>>> a.pop()
3
print(id(a))
>>> a
[1, 2]
>>> a = [1,2,3]
>>> a = a[:-1]
>>> a
print(id(a))
[1, 2]
>>>

id输出(数字无关紧要,重点是相同或不同):

4470627464
4470627464
4474450952

值得注意的是,由于pop会改变a所引用的列表,而切片操作会将a更新为引用新列表,因此当其他变量引用同一列表时,主要区别就出现了。 - Hamms

1

pop 方法返回从列表中删除的最后一项。 例如:

a = [1,2,3,4]
b = a.pop()
print(b)  # 4

此外,使用切片操作会创建旧列表的副本,而使用pop则保留了列表的引用。

1

在函数使用中存在一个基本差异。使用[:-1]不会改变原始列表,但是pop()可以。

a = [1,2,3]
b = [1,2,3]


def functionb(list):
    list = list[:-1]
    return list
def withpop(list):
    return list.pop()

functionb(b)
withpop(a)
print b
print a

将打印:

[1, 2, 3]
[1, 2]

第二个是执行时间。 pop()[:-1] 更快,因为当你使用 [:-1] 时,你必须覆盖列表。假设你有成千上万个值在索引中,所以它会比 pop() 慢。

0

是的,有区别。 当您使用a.pop()时,您也会从列表中删除 当您使用a[:-1]对象列表不会改变 检查len(a)

>>> a = [1,2,3]
>>> a
[1, 2, 3]
>>> a[:-1]
[1, 2]
>>> len(a[:-1])
2
>>> a.pop()
3
>>> a
[1, 2]
>>> len(a)
2
>>> 

0

从外观上看,你所展示的两种方式没有区别。 pop 指令使解释器更容易优化指令,因为它只需将列表的长度属性减少一个。而 -1 赋值将构造一个新列表,将其分配给 a,然后将旧列表留给垃圾回收。

在别名方面有很大的区别:如果你将其他东西分配给该列表,使用 pop 将会产生副作用。例如:

>>> a = [1, 2, 3, 4]
>>> b = a
>>> b
[1, 2, 3, 4]
>>> a.pop()
4
>>> b
[1, 2, 3]
>>> a = a[:-1]
>>> b
[1, 2, 3]
>>> a
[1, 2]

1
请注意,如果需要,切片也可以执行相同的副作用,只需将 a = a[:-1] 更改为 a[:] = a[:-1];而不是将 a 重新绑定到新的 list,将“空”切片赋值将用切片的结果替换原始 list内容 - ShadowRanger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接