关于python:连接两个列表-“+=”和extend()之间的差异

Concatenating two lists - difference between '+=' and extend()

我已经看到在python中有两种(可能更多)连接列表的方法:一种方法是使用extend()方法:

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

另一个使用加号(+)运算符:

1
b += a

现在我想知道:这两个选项中的哪一个是"pythonic"的列表连接方式,两者之间有什么区别(我已经查阅了官方的python教程,但找不到关于这个主题的任何内容)。


在字节码级别上唯一的区别是,.extend方式涉及函数调用,而在python中,函数调用比INPLACE_ADD稍微贵一些。

这真的没什么好担心的,除非你做了数十亿次这个操作。然而,瓶颈可能在其他地方。


对于非局部变量(非局部变量,也非全局变量)不能使用"+"。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def main():
    l = [1, 2, 3]

    def foo():
        l.extend([4])

    def boo():
        l += [5]

    foo()
    print l
    boo()  # this will fail

main()

这是因为for extend case编译器将使用LOAD_DEREF指令加载变量l,但对于+=它将使用LOAD_FAST,您将得到*UnboundLocalError: local variable 'l' referenced before assignment*


您可以链接函数调用,但不能直接+=函数调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class A:
    def __init__(self):
        self.listFoo = [1, 2]
        self.listBar = [3, 4]

    def get_list(self, which):
        if which =="Foo":
            return self.listFoo
        return self.listBar

a = A()
other_list = [5, 6]

a.get_list("Foo").extend(other_list)
a.get_list("Foo") += other_list  #SyntaxError: can't assign to function call

我会说,当它与numpy(我刚才看到的问题是关于连接两个列表,而不是numpy数组,但因为这可能是一个问题,如我初学者,我希望这可以帮助谁寻求解决这个帖子),为前。

1
2
3
4
import numpy as np
a = np.zeros((4,4,4))
b = []
b += a

它会错误地返回

值错误:操作数无法与形状(0,)一起广播(4,4,4)

b.extend(a)工作得很好


从python 3.5.2源代码:没有什么区别。

1
2
3
4
5
6
7
8
9
10
11
12
static PyObject *
list_inplace_concat(PyListObject *self, PyObject *other)
{
    PyObject *result;

    result = listextend(self, other);
    if (result == NULL)
        return result;
    Py_DECREF(result);
    Py_INCREF(self);
    return (PyObject *)self;
}

实际上,这三种选择之间存在差异:ADDINPLACE_ADDextend。前者总是较慢的,而另两个大致相同。

有了这些信息,我更愿意使用extend,它比ADD快,在我看来,它比INPLACE_ADD更明确地说明了你在做什么。

尝试以下代码几次(对于Python3):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import time

def test():
    x = list(range(10000000))
    y = list(range(10000000))
    z = list(range(10000000))

    # INPLACE_ADD
    t0 = time.process_time()
    z += x
    t_inplace_add = time.process_time() - t0

    # ADD
    t0 = time.process_time()
    w = x + y
    t_add = time.process_time() - t0

    # Extend
    t0 = time.process_time()
    x.extend(y)
    t_extend = time.process_time() - t0

    print('ADD {} s'.format(t_add))
    print('INPLACE_ADD {} s'.format(t_inplace_add))
    print('extend {} s'.format(t_extend))
    print()

for i in range(10):
    test()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
ADD 0.3540440000000018 s
INPLACE_ADD 0.10896000000000328 s
extend 0.08370399999999734 s

ADD 0.2024550000000005 s
INPLACE_ADD 0.0972940000000051 s
extend 0.09610200000000191 s

ADD 0.1680199999999985 s
INPLACE_ADD 0.08162199999999586 s
extend 0.0815160000000077 s

ADD 0.16708400000000267 s
INPLACE_ADD 0.0797719999999913 s
extend 0.0801490000000058 s

ADD 0.1681250000000034 s
INPLACE_ADD 0.08324399999999343 s
extend 0.08062700000000689 s

ADD 0.1707760000000036 s
INPLACE_ADD 0.08071900000000198 s
extend 0.09226200000000517 s

ADD 0.1668420000000026 s
INPLACE_ADD 0.08047300000001201 s
extend 0.0848089999999928 s

ADD 0.16659500000000094 s
INPLACE_ADD 0.08019399999999166 s
extend 0.07981599999999389 s

ADD 0.1710910000000041 s
INPLACE_ADD 0.0783479999999912 s
extend 0.07987599999999873 s

ADD 0.16435900000000458 s
INPLACE_ADD 0.08131200000001115 s
extend 0.0818660000000051 s


extend()可以与任何iterable*一起使用,+=可以与某些iterable*一起使用,但会变得很奇怪。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import numpy as np

l = [2, 3, 4]
t = (5, 6, 7)
l += t
l
[2, 3, 4, 5, 6, 7]

l = [2, 3, 4]
t = np.array((5, 6, 7))
l += t
l
array([ 7,  9, 11])

l = [2, 3, 4]
t = np.array((5, 6, 7))
l.extend(t)
l
[2, 3, 4, 5, 6, 7]

Python 3.6*很确定。extend()可以与任何iterable一起使用,但是如果我不正确,请注释。


根据python进行数据分析。

"请注意,通过添加进行列表连接是一个相对昂贵的操作,因为必须创建一个新列表并复制对象。使用extend将元素附加到现有列表中,尤其是在构建大型列表时,通常更可取。"因此,

1
2
3
everything = []
for chunk in list_of_lists:
    everything.extend(chunk)

比连接选项更快:

1
2
3
everything = []
for chunk in list_of_lists:
    everything = everything + chunk

enter image description hereenter image description here