2010-07-09 23 views
46

Por lo poco que sé, + op por listas solo requiere que el 2do operando sea iterable, lo que "ha" es claramente.Si x es la lista, ¿por qué funciona x + = "ha", mientras que x = x + "ha" arroja una excepción?

En código:

>>> x = [] 
>>> x += "ha" 
>>> x 
['h', 'a'] 
>>> x = x + "ha" 
Traceback (most recent call last): 
File "<stdin>", line 1, in <module> 
TypeError: can only concatenate list (not "str") to list 
+1

"estoy de acuerdo" con su pregunta; este es un buen argumento contra la sobrecarga del operador para mí. – u0b34a0f6ae

+0

Eliminé mi respuesta después de su edición, parece que se está preguntando sobre la razón detrás de no admitir + entre una lista y una iterable: mi error. Aparte de decir "Sí, ¿por qué no?", No tengo una respuesta. –

+3

que es una rotura * major *. de manera más general, cualquier lenguaje o biblioteca que defina comportamientos diferentes para operadores de aspecto similar debería considerarse hostil al usuario. nadie en su sano juicio usaría '+' para la concatenación de cadenas: ¡esa operación no es conmutativa! –

Respuesta

33

Usando += con una lista es como llamar extend, no +.

  • Puede llamar al extend con un iterable.
  • Solo puede usar + con otra lista.

Solo puedo adivinar por qué se tomó esta decisión, pero me imagino que es por motivos de rendimiento. Llamar al + da como resultado la creación de un nuevo objeto y la copia de todos los elementos, mientras que extend puede usar espacio libre en el objeto de la lista existente y, en algunos casos, guardar una copia.

Otro efecto secundario de esta decisión es que si escribe x += y, otras referencias a la lista verán el cambio, pero si usa x = x + y, entonces no lo harán. Esto se demuestra a continuación:

 
>>> x = ['a','b'] 
>>> y = ['c', d'] 
>>> z = x 
>>> x += y 
>>> z 
['a', 'b', 'c', 'd'] 

>>> x = ['a','b'] 
>>> y = ['c', d'] 
>>> z = x 
>>> x = x + y 
>>> z 
['a', 'b'] 

Referencias

Python source code for list.

El código fuente de +=:

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

El código fuente para +:

 
static PyObject * 
list_concat(PyListObject *a, PyObject *bb) 
{ 
    Py_ssize_t size; 
    Py_ssize_t i; 
    PyObject **src, **dest; 
    PyListObject *np; 
    if (!PyList_Check(bb)) { 
     PyErr_Format(PyExc_TypeError, 
        "can only concatenate list (not \"%.200s\") to list", 
        bb->ob_type->tp_name); 
     return NULL; 
    } 

    // etc ... 
+20

Creo que la verdadera pregunta aquí es: "¿por qué tanta inconsistencia?" – doublep

+0

estoy a punto de ir -1 en esta respuesta ya que no responde la pregunta en absoluto (vea el comentario de @ doublep). –

+5

No creo que esté claro en absoluto que esta pregunta es una crítica del diseño. El primer paso debe ser comprender cómo se implementa la inconsistencia, y esto es todo lo que podemos ayudar aquí. Las preguntas más grandes que ustedes comentan están completamente fuera del alcance de SO, si me preguntan :) –

8

Usted está pensando al revés. Se pregunta por qué x = x + 'ha' arroja una excepción, dado que x += 'ha' funciona. Realmente, la pregunta es por qué x += 'ha' funciona en absoluto.

Todo el mundo está de acuerdo (espero) que 'abc' + 'ha' y deberían funcionar. Y en estos casos, la sobrecarga de += para hacer modificaciones in situ parece razonable.

Los diseñadores de idiomas decidieron que [1, 2, 3] + 'ha' no debería, porque está mezclando diferentes tipos. Y eso parece razonable también.

Entonces la pregunta es por qué decidieron permitir mezclar diferentes tipos en el caso de x += 'ha'. En este caso, me imagino que hay un par de razones:

  • Es un método rápido y conveniente
  • Es obvio lo que sucede (anexar cada uno de los artículos en el iterable a x)

En general , Python intenta permitirte hacer lo que quieras, pero cuando hay ambigüedad, tiende a obligarte a ser explícito.

+2

otro tentativo -1: para mí es obvio que 'x + = y' se define como' x = x + y' para cualquier 'x' y' y'. de inmediato queda claro que has evitado responder la pregunta. ;) –

+6

Creo que el punto aquí es que * no * es obvio, de ahí la pregunta. En la mayoría de los demás lenguajes de programación donde se define tanto '+ =' como '+', hacer 'x + = y' generalmente se define como exactamente igual que' x = x + y'. De hecho, típicamente uno es un alias para el otro. –

+0

Es obvio en el sentido de que, si lo intenta, está muy claro lo que sucede. Y no es como si, si no esperaras que funcionara, te decepcionará cuando lo haga. –

5

Al definir operadores, hay dos operadores "agregar" diferentes: uno se llama __add__, el otro __iadd__. El último es para adiciones in-situ con +=, el otro es el operador regular +. http://docs.python.org/reference/datamodel.html tiene más información sobre eso.

Cuestiones relacionadas