Python的列表方法append和extend有什么区别?

3111

append()extend()这两个列表方法有什么不同?

20个回答

5853

.append() 将指定的对象附加到列表末尾:

>>> x = [1, 2, 3]
>>> x.append([4, 5])
>>> print(x)
[1, 2, 3, [4, 5]]

.extend()通过将指定的可迭代元素附加到列表末尾来扩展列表:

>>> x = [1, 2, 3]
>>> x.extend([4, 5])
>>> print(x)
[1, 2, 3, 4, 5]

171
在上面的示例中,extend 和简单使用加法运算符 + 的区别是什么? 答:extend 可以将一个可迭代对象中的元素添加到列表末尾,而使用 + 运算符则会创建一个新的列表并将两个列表连接起来。 - Rohan
410
实际上有一个很大的区别 - x + [4, 5] 给 x 分配了一个新列表 - x.extend() 则会改变原来的列表。我在下面的回答中详细说明。 - Russia Must Remove Putin
10
@AaronHall @Rohan 但这与 x += [4,5] 是相同的。 - Astitva Srivastava
2
使用append时的关键字是Object。如果您尝试使用extend并传入一个dictionary,它将会把key而不是整个哈希附加到数组末尾。 - Anthony
2
@Rohan,x = x + [4, 5] 的时间复杂度为 O(len(x) + len([4,5])),而 extend 的时间复杂度为 O(len([4, 5]))。 - mcagriardic
显示剩余2条评论

736

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

655

列表方法append和extend之间有什么区别?

  • .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()


22
确实是一个完美的答案。那么 l1 += l2l1.extend(l2) 的性能呢? - Jean-Francois T.
12
l1 += l2l1.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
4
+=必须重新分配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
3
本地测试中的简单比较:对于一个本地变量(因此 += 只是使用 STORE_FAST,非常便宜),其中被添加的值是一个已有一个项目的 list,操作重复 1000 次,+= 平均需要约 33 纳秒,而 extend 需要 78 纳秒,差异为 45 纳秒。如果 l1 是全局变量(需要更昂贵的 STORE_GLOBAL),差异缩小到 17 纳秒。如果 l1 实际上是 local.l1(需要更昂贵的 STORE_ATTR),则 +=extend 之间没有实质性的区别(计时大致相同;有时 extend 获胜)。 - ShadowRanger
1
@zk82:是的。它完成了整个操作,然后在重新赋值时失败了。最好避免使用它;我将被迫对任何实际使用 += 并只使用 try:/except TypeError: pass 来消除异常的人进行惩罚。 :-) - ShadowRanger
显示剩余6条评论

137

append用于添加单个元素。而extend用于添加一个元素列表。

需要注意的是,如果你将一个列表传递给append方法,它仍然只会添加这个列表作为一个元素:

>>> a = [1, 2, 3]
>>> a.append([4, 5, 6])
>>> a
[1, 2, 3, [4, 5, 6]]

93

追加 vs 扩展

enter image description here

使用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]

或者说,与append不同的是,extend可以一次性添加多个元素而不将列表嵌套到原始列表中(这就是extend名称的原因)。
>>> a.extend([4,5,6])
>>> a
[1,2,3,4,5,6]

使用两种方法添加一个元素

enter image description here

无论是 append 还是 extend,都可以将一个元素添加到列表的末尾,不过 append 更简单。

添加 1 个元素

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

使用extend方法时,你需要将列表作为参数传递,但是你将得到一个新元素不嵌套在旧元素中的列表。
>>> z = [1,2] 
>>> z.extend([3,4])
>>> z
[1,2,3,4]

因此,如果有更多的元素,您将使用extend方法获取一个包含更多项的列表。但是,添加一个列表不会向列表中添加更多的元素,而是一个嵌套列表作为一个元素,这在代码输出中可以清楚地看到。

enter image description here

enter image description here


67

以下两个代码片段在语义上是等效的:

for item in iterator:
    a_list.append(item)

并且

a_list.extend(iterator)

由于循环是用C语言实现的,后者可能更快。


22
在我的电脑上,使用“扩展”比在循环中“添加”要快4倍(对于100个零的循环,分别为16微秒和4微秒)。 - Alex L
6
extend() 可能会预先分配空间,而 append() 则很可能不会。 - Mad Physicist
@MadPhysicist:为了完整起见,有时 extend() 会无法明智地预先分配内存,因为某些可迭代对象没有实现 __len__(),但像你一样,如果它不尝试我会感到惊讶。正如 Aaron's answer 中指出的那样,一些性能提升也来自于使用纯 C 进行迭代部分而不是在 Python 中执行。 - Soren Bjornstad

47

append()方法将单个项添加到列表的末尾。

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


你不能只用6来扩展列表,因为它不可迭代。而且你的示例中第二个输出是错误的。'abc' 作为一个单独的元素添加到了列表中,因为你将它作为一个只有一个元素 ['abc'] 的列表传递给了 extend 方法:[1, 2, 3, 4, 5, 'abc']。如果要使你的示例输出正确,请将 abc 行更改为:x.extend('abc')。并删除 x.extend(6) 或将其更改为 x.extend([6]) - aneroid
还有,“extend()方法需要一个参数,即列表”是错误的。 - am70

41
您可以使用“+”来返回扩展,而不是在原地进行扩展。
l1=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]

类似于+=的原地操作,但与appendextend有轻微区别。其中最大的区别是当它在函数范围内使用时与appendextend不同,详见这篇博客文章


使用“+”来返回扩展是否会影响时间复杂度? - franklin
5
@franklin,请参考这个答案的详细信息:https://dev59.com/w3VC5IYBdhLWcg3wjx_u#28119966 - denfromufa
3
我不明白这个回答如何回应这个问题。 - pppery
我认为list.extend([item])list.append(item)更有效率。 - perpetualstudent

25

append(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]

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]

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