Si x es la lista, ¿por qué x + = “ha” funciona, mientras que x = x + “ha” lanza una excepción?

Por lo poco que sé, + op para listas solo requiere que el segundo operando sea iterable, lo que “ha” claramente es.

En codigo:

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

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

  • Puedes llamar extend con un iterable.
  • Solo puedes usar + con otra lista.

Solo puedo adivinar por qué se tomó esta decisión, pero me imagino que es por razones de rendimiento. Al llamar + se crea un nuevo objeto y se copian todos los elementos, mientras que extend puede usar el espacio libre en el objeto de lista existente, guardando una copia en algunos casos.

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

Código fuente de Python para la lista .

Código fuente para += :

 PyObject estático *
 list_inplace_concat (PyListObject * self, PyObject * other)
 {
     PyObject * resultado;

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

Código fuente para + :

 PyObject estático *
 list_concat (PyListObject * a, PyObject * bb)
 {
     Tamaño Py_ssize_t;
     Py_ssize_t i;
     PyObject ** src, ** dest;
     PyListObject * np;
     if (! PyList_Check (bb)) {
         PyErr_Format (PyExc_TypeError,
                   "solo puede concatenar la lista (no \"%. 200s \ ") para listar",
                   bb-> ob_type-> tp_name);
         devuelve NULL;
     }

     // etc ...

Estás pensando en eso al revés. Estás preguntando por qué x = x + 'ha' lanza una excepción, dado que x += 'ha' funciona. Realmente, la pregunta es por qué x += 'ha' funciona en absoluto.

Todos están de acuerdo (espero) que 'abc' + 'ha' y [1, 2, 3] + ['h', 'a'] deberían funcionar. Y en estos casos, la sobrecarga += para hacer modificaciones in situ parece razonable.

Los diseñadores de idiomas decidieron que [1, 2, 3] + 'ha' no deberían, porque estás 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 una taquigrafía conveniente
  • Es obvio lo que sucede (usted agrega cada uno de los elementos en el iterable a x )

En general, Python intenta dejarte hacer lo que quieres, pero donde hay ambigüedad, tiende a obligarte a ser explícito.

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