append()
和extend()
这两个列表方法有什么不同?
append()
和extend()
这两个列表方法有什么不同?
.append()
将元素添加到列表中,
而 .extend()
将第一个列表与另一个列表 / 可迭代对象连接起来。
>>> xs = ['A', 'B']
>>> xs
['A', 'B']
>>> xs.append("D")
>>> xs
['A', 'B', 'D']
>>> xs.append(["E", "F"])
>>> xs
['A', 'B', 'D', ['E', 'F']]
>>> xs.insert(2, "C")
>>> xs
['A', 'B', 'C', 'D', ['E', 'F']]
>>> xs.extend(["G", "H"])
>>> xs
['A', 'B', 'C', 'D', ['E', 'F'], 'G', 'H']
.append()
将其参数作为单个元素添加到列表末尾。列表本身的长度将增加一个。.extend()
迭代其参数,将每个元素添加到列表中,扩展列表。列表的长度将增加与可迭代参数中的元素数量相同。.append()
.append()
方法将对象附加到列表末尾。
my_list.append(object)
my_list
的末尾。>>> my_list
['foo', 'bar']
>>> my_list.append('baz')
>>> my_list
['foo', 'bar', 'baz']
>>> another_list = [1, 2, 3]
>>> my_list.append(another_list)
>>> my_list
['foo', 'bar', 'baz', [1, 2, 3]]
#^^^^^^^^^--- single item at the end of the list.
.extend()
.extend()
方法通过从可迭代对象中添加元素来扩展列表:
my_list.extend(iterable)
使用extend方法,可将可迭代对象中的每个元素添加到列表中。例如:
>>> my_list
['foo', 'bar']
>>> another_list = [1, 2, 3]
>>> my_list.extend(another_list)
>>> my_list
['foo', 'bar', 1, 2, 3]
>>> my_list.extend('baz')
>>> my_list
['foo', 'bar', 1, 2, 3, 'b', 'a', 'z']
__add__
(+
)和 __iadd__
(+=
)list
对象定义了 +
和 +=
运算符。它们在语义上类似于 extend
。
my_list + another_list
会创建第三个列表,因此您可以返回其结果,但需要保证第二个可迭代对象是一个列表。
my_list += another_list
则修改了原有的列表(它是原地操作符,且列表是可变对象,正如我们所见),因此不会创建新列表。它的工作方式也类似于 extend
,因为第二个可迭代对象可以是任何类型的可迭代对象。
不要混淆 - my_list = my_list + another_list
并不等同于 +=
- 它会给 my_list 分配一个全新的列表。
Append操作的时间复杂度是均摊 常数时间复杂度,即O(1)。
而Extend操作的时间复杂度为O(k)。
如果您需要对一个列表进行多次添加操作(即多次调用.append()
函数),那么添加操作的时间复杂度会增加,达到与Extend操作相同的级别。因此,如果您打算将来自可迭代对象的多个项添加到列表中,使用Extend操作会更快,因为其内部迭代是由C实现的。
关于“均摊”- 来自list object implementation source:
/* This over-allocates proportional to the list size, making room
* for additional growth. The over-allocation is mild, but is
* enough to give linear-time amortized behavior over a long
* sequence of appends() in the presence of a poorly-performing
* system realloc().
这意味着我们可以提前获得比需要更大的内存重新分配的好处,但在下一个边际重新分配时,我们可能会为此付出更大的代价。所有追加操作的总时间为O(n),每个追加操作所分配的时间变为O(1)。
您可能想知道哪个更高效,因为append可以用于实现与extend相同的结果。以下函数执行相同的操作:
def append(alist, iterable):
for item in iterable:
alist.append(item)
def extend(alist, iterable):
alist.extend(iterable)
那么让我们来计时它们:
import timeit
>>> min(timeit.repeat(lambda: append([], "abcdefghijklmnopqrstuvwxyz")))
2.867846965789795
>>> min(timeit.repeat(lambda: extend([], "abcdefghijklmnopqrstuvwxyz")))
0.8060121536254883
一位评论者说:
完美的答案,我只是错过了比较添加一个元素的时机
做正确的语义操作。如果你想要将可迭代对象中的所有元素追加到列表中,请使用.extend()
。如果你只是添加一个元素,请使用.append()
。
好的,那么让我们创建一个实验来看看这在时间上的表现:
def append_one(a_list, element):
a_list.append(element)
def extend_one(a_list, element):
"""creating a new list is semantically the most direct
way to create an iterable to give to extend"""
a_list.extend([element])
import timeit
我们可以看到,为了使用extend而特意创建一个可迭代对象是一种(轻微的)浪费时间:
>>> min(timeit.repeat(lambda: append_one([], 0)))
0.2082819009956438
>>> min(timeit.repeat(lambda: extend_one([], 0)))
0.2397019260097295
从中我们学到,当我们只有一个要添加的元素时,使用.extend()
没有任何收益。
此外,这些时间不是那么重要。我只是为了说明,在Python中,做语义上正确的事情就是以正确的方式做事。
有可能您会在两个可比较的操作上测试时间并获得模糊或相反的结果。只需专注于做语义上正确的事情即可。
我们看到.extend()
在语义上更清晰,并且当您打算将迭代器中的每个元素附加到列表中时,它可以运行得比.append()
快得多。
如果您只有一个要添加到列表中的单个元素(而不是迭代器),请使用.append()
。
l1 += l2
和 l1.extend(l2)
的性能呢? - Jean-Francois T.l1 += l2
和 l1.extend(l2)
最终执行的是相同的代码(在 listobject.c
中的 list_extend
函数)。唯一的区别是:1. +=
重新分配了 l1
(对于 list
是赋值给其自身,但对于不是同一对象的不可变类型则不是),如果 l1
实际上是不可变对象的属性,则会导致错误;例如,t = ([],)
,t[0] += lst
将失败,而 t[0].extend(lst)
将起作用。 2. l1 += l2
使用专用字节码,而 l1.extend(l2)
使用通用方法调度;这使得 +=
比 extend
更快。 - ShadowRanger+=
必须重新分配l1
这一事实意味着,在某些情况下,相对较慢的extend
调度部分或全部弥补了不向左侧重新赋值的缺陷。例如,如果“list”是对象的属性,则在我的Python 3.6安装上,“self.l1 += l2”和“self.l1.extend(l2)”具有相同的性能,因为真正的操作更像是“self.l1 = self.l1.iadd(l2)”,这意味着它必须执行一个中等昂贵的“STORE_ATTR”,而“self.l1.extend(l2)”则没有。 - ShadowRanger+=
只是使用 STORE_FAST
,非常便宜),其中被添加的值是一个已有一个项目的 list
,操作重复 1000 次,+=
平均需要约 33 纳秒,而 extend
需要 78 纳秒,差异为 45 纳秒。如果 l1
是全局变量(需要更昂贵的 STORE_GLOBAL
),差异缩小到 17 纳秒。如果 l1
实际上是 local.l1
(需要更昂贵的 STORE_ATTR
),则 +=
和 extend
之间没有实质性的区别(计时大致相同;有时 extend
获胜)。 - ShadowRanger+=
并只使用 try:
/except TypeError: pass
来消除异常的人进行惩罚。 :-) - ShadowRangerappend
用于添加单个元素。而extend
用于添加一个元素列表。
需要注意的是,如果你将一个列表传递给append
方法,它仍然只会添加这个列表作为一个元素:
>>> a = [1, 2, 3]
>>> a.append([4, 5, 6])
>>> a
[1, 2, 3, [4, 5, 6]]
使用append,您可以附加一个单独的元素,它将扩展列表:
>>> a = [1,2]
>>> a.append(3)
>>> a
[1,2,3]
如果您想扩展多个元素,则应使用extend,因为您只能附加一个元素或一个元素列表:
>>> a.append([4,5])
>>> a
>>> [1,2,3,[4,5]]
这样,你就能得到一个嵌套的列表
而使用extend,你可以像这样扩展单个元素
>>> a = [1,2]
>>> a.extend([3])
>>> a
[1,2,3]
>>> a.extend([4,5,6])
>>> a
[1,2,3,4,5,6]
无论是 append 还是 extend,都可以将一个元素添加到列表的末尾,不过 append 更简单。
>>> x = [1,2]
>>> x.append(3)
>>> x
[1,2,3]
>>> x = [1,2]
>>> x.extend([3])
>>> x
[1,2,3]
如果您使用append添加多个元素,您需要将它们作为列表传递,并且您将获得一个嵌套的列表!
>>> x = [1,2]
>>> x.append([3,4])
>>> x
[1,2,[3,4]]
>>> z = [1,2]
>>> z.extend([3,4])
>>> z
[1,2,3,4]
因此,如果有更多的元素,您将使用extend方法获取一个包含更多项的列表。但是,添加一个列表不会向列表中添加更多的元素,而是一个嵌套列表作为一个元素,这在代码输出中可以清楚地看到。
以下两个代码片段在语义上是等效的:
for item in iterator:
a_list.append(item)
并且
a_list.extend(iterator)
由于循环是用C语言实现的,后者可能更快。
extend()
可能会预先分配空间,而 append()
则很可能不会。 - Mad Physicistextend()
会无法明智地预先分配内存,因为某些可迭代对象没有实现 __len__()
,但像你一样,如果它不尝试我会感到惊讶。正如 Aaron's answer 中指出的那样,一些性能提升也来自于使用纯 C 进行迭代部分而不是在 Python 中执行。 - Soren Bjornstadappend()
方法将单个项添加到列表的末尾。
x = [1, 2, 3]
x.append([4, 5])
x.append('abc')
print(x)
# gives you
[1, 2, 3, [4, 5], 'abc']
extend()
方法接受一个列表作为参数,并将参数中的每个项附加到原始列表中。(列表是作为类实现的。"创建"一个列表实际上是实例化一个类。因此,列表具有对其进行操作的方法。)
x = [1, 2, 3]
x.extend([4, 5])
x.extend('abc')
print(x)
# gives you
[1, 2, 3, 4, 5, 'a', 'b', 'c']
来自 《Python 禅》。
['abc']
的列表传递给了 extend
方法:[1, 2, 3, 4, 5, 'abc']。如果要使你的示例输出正确,请将 abc 行更改为:x.extend('abc')
。并删除 x.extend(6)
或将其更改为 x.extend([6])
。 - aneroidl1=range(10)
l1+[11]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11]
l2=range(10,1,-1)
l1+l2
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 9, 8, 7, 6, 5, 4, 3, 2]
类似于+=
的原地操作,但与append
和extend
有轻微区别。其中最大的区别是当它在函数范围内使用时与append
和extend
不同,详见这篇博客文章。
list.extend([item])
比list.append(item)
更有效率。 - perpetualstudentappend(object)
方法通过将对象添加到列表中来更新列表。
x = [20]
# List passed to the append(object) method is treated as a single object.
x.append([21, 22, 23])
# Hence the resultant list length will be 2
print(x)
--> [20, [21, 22, 23]]
extend(list)
将两个列表连接起来。
x = [20]
# The parameter passed to extend(list) method is treated as a list.
# Eventually it is two lists being concatenated.
x.extend([21, 22, 23])
# Here the resultant list's length is 4
print(x)
--> [20, 21, 22, 23]
extend()
可以与迭代器参数一起使用,这里有一个示例。你想用一个列表的列表来创建一个列表:
从
list2d = [[1,2,3],[4,5,6], [7], [8,9]]
您想要什么?
>>>
[1, 2, 3, 4, 5, 6, 7, 8, 9]
您可以使用 itertools.chain.from_iterable()
来实现这一点。此方法的输出是一个迭代器,其实现等效于
def from_iterable(iterables):
# chain.from_iterable(['ABC', 'DEF']) --> A B C D E F
for it in iterables:
for element in it:
yield element
回到我们的例子,我们可以这样做
import itertools
list2d = [[1,2,3],[4,5,6], [7], [8,9]]
merged = list(itertools.chain.from_iterable(list2d))
获取所需列表。
以下是如何使用迭代器参数等效地使用extend()
:
merged = []
merged.extend(itertools.chain.from_iterable(list2d))
print(merged)
>>>
[1, 2, 3, 4, 5, 6, 7, 8, 9]
extend
和简单使用加法运算符+
的区别是什么? 答:extend
可以将一个可迭代对象中的元素添加到列表末尾,而使用+
运算符则会创建一个新的列表并将两个列表连接起来。 - Rohanx + [4, 5]
给 x 分配了一个新列表 -x.extend()
则会改变原来的列表。我在下面的回答中详细说明。 - Russia Must Remove Putinx += [4,5]
是相同的。 - Astitva Srivastavaappend
时的关键字是Object。如果您尝试使用extend
并传入一个dictionary,它将会把key而不是整个哈希附加到数组末尾。 - Anthony