ChatGPT解决这个技术问题 Extra ChatGPT

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

这个问题的答案是社区的努力。编辑现有答案以改进这篇文章。它目前不接受新的答案或交互。

列表方法 append()extend() 有什么区别?


M
Mateen Ulhaq

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]

extend 和仅使用加法运算符(在上面的示例中为 x = x + [4, 5])有什么区别?
实际上有一个很大的不同 - x + [4, 5] 为您提供了一个分配给 x 的新列表 - x.extend() 改变了原始列表。我在下面的答案中详细说明。
@AaronHall @Rohan 但它与 x += [4,5] 相同。
使用 append 时的关键字是 Object。如果您尝试使用 extend 并传入 dictionary,它会将 key 而不是整个哈希附加到数组的末尾。
@Rohan, x = x + [4, 5] 的时间复杂度为 O(len(x) + len([4,5])) 其中 extend 的时间复杂度为 O(len([4, 5 ]))
M
Mateen Ulhaq

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

R
Russia Must Remove Putin

列表方法追加和扩展有什么区别?

append 将其参数作为单个元素添加到列表的末尾。列表本身的长度将增加一。

extend 迭代其参数,将每个元素添加到列表中,扩展列表。无论可迭代参数中有多少元素,列表的长度都会增加。

附加

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

延长

list.extend 方法通过附加来自可迭代对象的元素来扩展列表:

my_list.extend(iterable)

因此,通过扩展,可迭代的每个元素都被附加到列表中。例如:

>>> 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 定义的。它们在语义上类似于扩展。

my_list + another_list 在内存中创建第三个列表,因此您可以返回它的结果,但它要求第二个可迭代对象是一个列表。

my_list += another_list 就地修改列表(它就地运算符,并且列表是可变对象,正如我们所见),因此它不会创建新列表。它也像extend一样工作,因为第二个iterable可以是任何类型的iterable。

不要混淆 - my_list = my_list + another_list 不等同于 += - 它为您提供分配给 my_list 的全新列表。

时间复杂度

追加有 (amortized) constant time complexity, 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

而且我们看到,为了使用扩展而特意创建一个可迭代的对象是(轻微的)时间浪费:

>>> min(timeit.repeat(lambda: append_one([], 0)))
0.2082819009956438
>>> min(timeit.repeat(lambda: extend_one([], 0)))
0.2397019260097295

我们从中了解到,当我们只有 一个 元素要附加时,使用 extend 没有任何好处。

此外,这些时间并不那么重要。我只是向他们表明,在 Python 中,做语义正确的事情就是用正确的方式做事™。

可以想象,您可能会在两个可比较的操作上测试时序并得到模棱两可或相反的结果。只专注于做语义上正确的事情。

结论

我们看到 extend 在语义上更清晰,并且它可以比 append 运行得更快,当您打算将迭代中的每个元素附加到列表时。

如果您只有一个元素(不在迭代中)要添加到列表中,请使用 append


@Aaron Hall 关于计时算法的一个小评论。 “extend_one”可能会返回“稍微错误”的时间,因为还涉及到列表的创建。如果您想更加严格,最好将项目创建为变量(ex1 = 0ex2 = [0])并传递这些变量。
确实是完美的答案。 l1 += l2l1.extend(l2) 的性能如何?
@Jean-FrancoisT.:l1 += l2l1.extend(l2) 最终执行相同的代码(listobject.c 中的 list_extend 函数)。唯一的区别是: 1. += 重新分配 l1(对于 list s,但重新分配支持不可变类型,之后不是同一个对象),如果 l1 实际上是不可变对象的属性;例如,t = ([],)t[0] += lst 会失败,而 t[0].extend(lst) 会起作用。 2. l1 += l2 使用专用字节码,而 l1.extend(l2) 使用通用方法调度;这使得 +=extend 快。
+= 必须重新分配 l1 的事实确实意味着在某些情况下,extend 的较慢调度部分或全部通过不分配回左侧来弥补。例如,如果 list 是一个对象的属性,则 self.l1 += l2self.l1.extend(l2) 在我的 Python 3.6 安装上具有相同的性能,仅仅是因为实际操作更像 self.l1 = self.l1.__iadd__(l2),这意味着它必须执行适度昂贵的STORE_ATTRself.l1.extend(l2) 则不必。
本地测试中的简单比较:对于一个本地变量(因此 += 只是使用 STORE_FAST,它非常便宜),其中要添加的值是一个现有的 list,其中包含一个项目,重复操作1000 次,+= 平均耗时约 33 ns,而 extend 耗时 78 ns,相差 45 ns。如果 l1 是全局的(需要更昂贵的 STORE_GLOBAL),则差异缩小到 17 ns。如果 l1 实际上是 local.l1(需要更昂贵的 STORE_ATTR),则 +=extend 之间没有有意义的区别(时间大致相同;extend 有时会胜出)。
G
Greg Hewgill

append 附加一个元素。 extend 附加元素列表。

请注意,如果您传递一个列表来追加,它仍然会添加一个元素:

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

C
Clint Chelak

追加与扩展

使用 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 更简单。

追加 1 个元素

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

扩展一个元素

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

添加更多元素...具有不同的结果

如果您对多个元素使用 append,则必须将元素列表作为参数传递,您将获得一个 NESTED 列表!

>>> 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 来获取包含更多项目的列表。但是,追加列表不会向列表中添加更多元素,而是添加一个嵌套列表的元素,您可以在代码输出中清楚地看到。

https://i.stack.imgur.com/lJK1M.png

https://i.stack.imgur.com/KC2Ji.png


K
Kenly

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

for item in iterator:
    a_list.append(item)

a_list.extend(iterator)

后者可能会更快,因为循环是用 C 实现的。


在我的机器上扩展比在循环中附加快约 4 倍(16us 对 4us 用于 100 个零循环)
extend() 可能预分配,而 append() 可能没有。
@MadPhysicist:为了完整起见,有时 extend() 无法 明智地预先分配,因为某些迭代没有实现 __len__(),但像你一样,如果它没有实现,我会感到惊讶不要尝试。正如 Aaron's answer 中所指出的,一些性能提升还来自于在纯 C 中而不是在 Python 中执行迭代部分。
G
Georgy

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

来自 Dive Into Python


您不能仅使用 6 进行扩展,因为它不可迭代。您示例中的第二个输出是错误的。 'abc' 被添加为单个元素,因为您将它作为具有一个元素 ['abc'] 的列表传递给 extend:[1, 2, 3, 4, 5, 'abc']。要使示例输出正确,请将 abc 行更改为:x.extend('abc')。并删除 x.extend(6) 或将其更改为 x.extend([6])
“extend() 方法接受一个参数,一个列表”也是错误的
P
Prakhar Trivedi

您可以使用“+”返回扩展,而不是就地扩展。

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]

+= 类似,用于就地行为,但与 append & 略有不同extend+=appendextend 的最大区别之一是它用于函数范围时,请参阅 this blog post


使用“+”返回扩展对时间复杂度有影响吗?
@franklin,有关详细信息,请参阅此答案:stackoverflow.com/a/28119966/2230844
我不明白这是如何回答问题的
P
Peter Mortensen

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]

P
Peter Mortensen

这相当于使用 + 运算符的 appendextend

>>> x = [1,2,3]
>>> x
[1, 2, 3]
>>> x = x + [4,5,6] # Extend
>>> x
[1, 2, 3, 4, 5, 6]
>>> x = x + [[7,8]] # Append
>>> x
[1, 2, 3, 4, 5, 6, [7, 8]]

P
Peter Mortensen

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]

B
Bahrom

append():在Python中基本上是用来添加一个元素的。

示例 1:

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

示例 2:

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

extend():其中extend(),用于合并两个列表或在一个列表中插入多个元素。

示例 1:

>> a = [1, 2, 3, 4]
>> b = [5, 6, 7, 8]
>> a.extend(b)
>> print(a)
>> a = [1, 2, 3, 4, 5, 6, 7, 8]

示例 2:

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

b
bconstanzo

已经暗示但未解释的一个有趣的点是extend 比append 快。对于任何内部有 append 的循环,都应该考虑用 list.extend(processed_elements) 替换。

请记住,追加新元素可能会导致整个列表重新分配到内存中更好的位置。如果因为我们一次添加 1 个元素而多次这样做,则整体性能会受到影响。从这个意义上说,list.extend 类似于 "".join(stringlist)。


P
Peter Mortensen

追加一次添加整个数据。整个数据将被添加到新创建的索引中。另一方面,extend,顾名思义,扩展了当前数组。

例如

list1 = [123, 456, 678]
list2 = [111, 222]

使用 append,我们得到:

result = [123, 456, 678, [111, 222]]

extend 上,我们得到:

result = [123, 456, 678, 111, 222]

G
Gavriel Cohen

英语词典将单词 appendextend 定义为:

append:在书面文件的末尾添加(某物)。扩大:变大。放大或扩大

有了这些知识,现在让我们了解

1) appendextend的区别

append

将任何 Python 对象按原样附加到列表的末尾(即作为列表中的最后一个元素)。

结果列表可能是嵌套的并包含异构元素(即列表、字符串、元组、字典、集合等)

extend

接受任何可迭代作为其参数并使列表更大。

结果列表始终是一维列表(即没有嵌套),并且由于应用 list(iterable),它可能包含异构元素(例如字符、整数、浮点数)。

2) appendextend 之间的相似性

两者都只接受一个论点。

两者都就地修改列表。

结果,两者都返回 None。

例子

lis = [1, 2, 3]

# 'extend' is equivalent to this
lis = lis + list(iterable)

# 'append' simply appends its argument as the last element to the list
# as long as the argument is a valid Python object
list.append(object)

P
Peter Mortensen

我希望我可以对这个问题做一个有用的补充。如果您的列表存储了特定类型的对象,例如 Info,那么 extend 方法不适合的情况是:在 for 循环中,并且每次生成一个 Info 对象并使用 extend 来将其存储到您的列表中,它将失败。例外情况如下:

TypeError:“信息”对象不可迭代

但是如果使用append方法,结果是OK的。因为每次使用 extend 方法时,它总会把它当作一个列表或任何其他集合类型,对其进行迭代,并将其放在上一个列表之后。很明显,一个特定的对象不能被迭代。


A
AbstProcDo

直观地区分它们

l1 = ['a', 'b', 'c']
l2 = ['d', 'e', 'f']
l1.append(l2)
l1
['a', 'b', 'c', ['d', 'e', 'f']]

这就像 l1 在她的身体内复制一个身体(嵌套)。

# Reset l1 = ['a', 'b', 'c']
l1.extend(l2)
l1
['a', 'b', 'c', 'd', 'e', 'f']

就像两个分开的人结婚并建立一个团结的家庭。

此外,我制作了所有列表方法的详尽备忘单供您参考。

list_methods = {'Add': {'extend', 'append', 'insert'},
                'Remove': {'pop', 'remove', 'clear'}
                'Sort': {'reverse', 'sort'},
                'Search': {'count', 'index'},
                'Copy': {'copy'},
                }

G
Georgy

extend(L) 通过附加给定列表 L 中的所有项目来扩展列表。

>>> a
[1, 2, 3]
a.extend([4])  #is eqivalent of a[len(a):] = [4]
>>> a
[1, 2, 3, 4]
a = [1, 2, 3]
>>> a
[1, 2, 3]
>>> a[len(a):] = [4]
>>> a
[1, 2, 3, 4]

i
ilias iliadis

append 通过仅一项(作为参数传递的单个对象)“扩展”列表(就地)。

extend 通过与传递的对象(作为参数)所包含的一样多的项目“扩展”列表(就地)。

对于 str 对象,这可能会有些混乱。

如果您将字符串作为参数传递: append 将在末尾添加单个字符串项,但 extend 将添加与该字符串长度一样多的“单个”“str”项。如果您将字符串列表作为参数传递:append 仍将在末尾添加一个“列表”项,而 extend 将添加与传递列表的长度一样多的“列表”项。

def append_o(a_list, element): a_list.append(element) print('append:', end = '') for item in a_list: print(item, end = ',') print() def extend_o(a_list, element ): a_list.extend(element) print('extend:', end = ' ') 对于 a_list 中的项目: print(item, end = ',') print() append_o(['ab'],'cd') extend_o(['ab'],'cd') append_o(['ab'],['cd', 'ef']) extend_o(['ab'],['cd', 'ef']) append_o( ['ab'],['cd']) extend_o(['ab'],['cd'])

产生:

append: ab,cd,
extend: ab,c,d,
append: ab,['cd', 'ef'],
extend: ab,cd,ef,
append: ab,['cd'],
extend: ab,cd,

您可以查看我在 Python 中解释扩展和追加的重新编码:youtu.be/8A5ohA-UeiI
v
vivek

追加和扩展是python中的可扩展机制之一。

追加:将一个元素添加到列表的末尾。

my_list = [1,2,3,4]

要将新元素添加到列表中,我们可以通过以下方式使用 append 方法。

my_list.append(5)

添加新元素的默认位置始终位于 (length+1) 位置。

插入:插入方法用于克服附加的限制。使用插入,我们可以明确定义我们希望插入新元素的确切位置。

insert(index, object) 的方法描述符。它有两个参数,第一个是我们要插入元素的索引,第二个是元素本身。

Example: my_list = [1,2,3,4]
my_list[4, 'a']
my_list
[1,2,3,4,'a']

扩展:当我们想要将两个或多个列表连接成一个列表时,这非常有用。如果没有扩展,如果我们想连接两个列表,结果对象将包含一个列表列表。

a = [1,2]
b = [3]
a.append(b)
print (a)
[1,2,[3]]

如果我们尝试访问 pos 2 处的元素,我们会得到一个列表 ([3]),而不是元素。要加入两个列表,我们必须使用 append。

a = [1,2]
b = [3]
a.extend(b)
print (a)
[1,2,3]

加入多个列表

a = [1]
b = [2]
c = [3]
a.extend(b+c)
print (a)
[1,2,3]