2010-09-06 25 views
151

que he visto en realidad hay dos (quizás más) formas de concatenar las listas en Python: Una forma es utilizar el método extend():La concatenación de dos listas - diferencia entre '+ =' y extender()

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

el otro para utilizar el signo más (+) del operador:

b += a 

Ahora me pregunto: ¿Cuál de estas dos opciones es la forma 'Pythonic' para hacer la lista de concatenación y hay una diferencia entre los dos (He buscado el tutorial oficial de Python pero no pude encontrar nada sobre este tema).

+0

Tal vez la diferencia tiene implicaciones más cuando se trata de Duck Typing y si su * quizá-no-muy-a-lista-pero-como-un-list * soporta '.__ iadd __()' /'.__add__() '/' .__ radd __() 'versus' .extend() ' –

+0

¡Las parejas de Q & A perfectas se votan por igual! – Viney

Respuesta

150

La única diferencia en un nivel de bytecode es que el modo .extend implica una llamada de función, que es un poco más costosa en Python que el INPLACE_ADD.

No es nada de lo que deba preocuparse, a menos que realice esta operación miles de millones de veces. Sin embargo, es probable que el cuello de botella se encuentre en otro lugar.

+9

Quizás la diferencia tenga más implicaciones cuando se trata de la identificación de patos y si su * quizás-no-realmente-una-lista-pero-como-una-lista * admite '.__ iadd __()'/'.__ add __()'/' .__ radd __() 'versus' .extend() ' –

+1

Esta respuesta no menciona las importantes diferencias de alcance. – wim

12

De acuerdo con la Zen of Python:

Simple is better than complex.

b += a es más simple que b.extend(a).

Las construcciones internas están tan optimizadas que no existe una diferencia de rendimiento real.

+7

'Debería haber una, y preferiblemente solo una, forma obvia de hacerlo'. ¿Rompe esto la regla entonces? – Zenadix

+1

@Zenadix Creo que solo existen estas pequeñas diferencias graciosas como la respuesta de monitorius shows. – Trilarion

+3

Esa no es una regla. Desearía que la gente no tomara tan en serio el Zen de Python: no tiene implementación. Considere el Zen como pautas, no las líneas de tranvía – holdenweb

107

No puede utilizar + = para la variable no local (variable que no es local para la función y tampoco mundial)

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

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

    def boo(): 
     l += [5] 

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

main() 

Es porque para extender compilador caso se carga la variable l usando LOAD_DEREF instrucción, pero por + = utilizará LOAD_FAST - y se obtiene *UnboundLocalError: local variable 'l' referenced before assignment*

+1

Tengo dificultades con su explicación "variable que ** no es local ** para la función y también ** no global **" ¿podría dar un ejemplo de dicha variable? –

+5

La variable 'l' en mi ejemplo es exactamente de ese tipo. No es local para las funciones 'foo' y 'boo' (fuera de sus ámbitos), pero no es global (definido dentro del func 'principal', no en el nivel de módulo) – monitorius

+1

Puedo confirmar que este error aún ocurre con python 3.4.2 (Necesitará agregar paréntesis para imprimir, pero todo lo demás puede permanecer igual). – trichoplax

13

puede llamadas a funciones de cadena, pero no se puede + = una llamada de función directa:

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 
4

Diría que hay algo de diferencia cuando se trata de numpy (Acabo de ver que la pregunta es acerca de concatenar dos listas, no numpy array, pero dado que podría ser un problema para principiantes, como yo, Espero que esto pueda ayudar a alguien que busque la solución a esta publicación), por ej.

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

volverá con el error

ValueError: operandos no podían ser transmitidos junto con formas (0), (4,4,4)

b.extend(a) funciona perfectamente

2

De pitón 3.5.2 código fuente: No hay gran diferencia.

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; 
} 
Cuestiones relacionadas