web-dev-qa-db-fra.com

Concaténation de deux listes - différence entre '+ =' et extend ()

J'ai vu qu'il y avait en fait deux façons (peut-être plus) de concaténer des listes en Python: Une façon consiste à utiliser la méthode extend ():

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

l'autre à utiliser l'opérateur plus (+):

b += a

Maintenant, je me demande: laquelle de ces deux options est la manière 'Pythonic' de faire une concaténation de liste et existe-t-il une différence entre les deux (j'ai consulté le tutoriel officiel de Python mais je n'ai rien trouvé à ce sujet).

185
helpermethod

La seule différence entre les niveaux de code source est que le chemin .extend implique un appel de fonction, ce qui est légèrement plus coûteux en Python que le INPLACE_ADD .

Ce n’est vraiment rien qui vous préoccupe, à moins d’effectuer cette opération des milliards de fois. Il est toutefois probable que le goulot d'étranglement se situe ailleurs.

178
SilentGhost

Vous ne pouvez pas utiliser + = pour une variable non locale (variable qui n'est pas locale pour une fonction ni aussi globale)

def main():
    l = [1, 2, 3]

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

    def boo():
        l += [5]

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

main()

C'est parce que pour extend case, le compilateur chargera la variable l à l'aide de l'instruction LOAD_DEREF, mais pour + =, il utilisera LOAD_FAST - et vous obtiendrez *UnboundLocalError: local variable 'l' referenced before assignment*.

145
monitorius

Vous pouvez chaîner des appels de fonction, mais vous ne pouvez pas + = directement un appel de fonction:

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
28
isarandi

Je dirais qu’il ya une différence en ce qui concerne numpy (je viens de voir que la question concerne la concaténation de deux listes, pas de tableau numpy, mais comme cela pourrait être un problème pour les débutants qui cherchent la solution à ce post), par ex.

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

il reviendra avec une erreur

ValueError: les opérandes ne peuvent pas être diffusés avec des formes (0,) (4,4,4)

b.extend(a) fonctionne parfaitement

7
Lance Ruo Zhang

Depuis le code source de python 3.5.2: Pas de grande différence.

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;
}
4
VicX

extend () fonctionne avec n'importe quel *, + = avec certains, mais peut devenir funky. 

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
* à peu près sûr. 

1
grofte

En réalité, il existe des différences entre les trois options: ADD, INPLACE_ADD et extend. Le premier est toujours plus lent, alors que les deux autres sont à peu près les mêmes.

Avec cette information, je préférerais utiliser extend, qui est plus rapide que ADD et qui me semble plus explicite que INPLACE_ADD.

Essayez le code suivant plusieurs fois (pour Python 3):

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()
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
0
dalonsoa

Selon le Python pour l'analyse des données.

«Notez que la concaténation de listes par ajout est une opération relativement coûteuse puisqu’une nouvelle liste doit être créée et les objets copiés. Il est généralement préférable d'utiliser extend pour ajouter des éléments à une liste existante, en particulier si vous créez une grande liste. " Ainsi,

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

est plus rapide que l'alternative concaténative:

everything = []
for chunk in list_of_lists:
    everything = everything + chunk

 enter image description here  enter image description here

0
littlebear333