¿Es i = i + n realmente lo mismo que i + = n?

Un bloque de código funciona, pero el otro no. Lo que tendría sentido excepto el segundo bloque es el mismo que el primero solo con una operación escrita en taquigrafía. Son prácticamente la misma operación.

l = ['table'] i = [] 

Versión 1

 for n in l: i += n print(i) 

Salida: ['t', 'a', 'b', 'l', 'e']

Versión 2

 for n in l: i = i + n print(i) 

Salida:

TypeError: solo puede concatenar lista (no “str”) para listar


¿Qué está causando este extraño error?

No tienen que ser los mismos.

El uso del operador + llama al método __add__ mientras que el operador += llama __iadd__ . Depende completamente del objeto en cuestión lo que sucede cuando se llama a uno de estos métodos.

Si usa x += y pero x no proporciona un método __iadd__ (o el método devuelve No NotImplemented ), __add__ se usa como reserva , lo que significa que x = x + y sucede.

En el caso de las listas, el uso de l += iterable realidad extiende la lista l con los elementos de iterable . En su caso, cada carácter de la cadena (que es un iterable) se anexa durante la operación de extend .

Demo 1: utilizando __iadd__

 >>> l = [] >>> l += 'table' >>> l ['t', 'a', 'b', 'l', 'e'] 

Demo 2: usar extend hace lo mismo

 >>> l = [] >>> l.extend('table') >>> l ['t', 'a', 'b', 'l', 'e'] 

Demo 3: agregar una lista y una cadena genera un TypeError .

 >>> l = [] >>> l = l + 'table' [...] TypeError: can only concatenate list (not "str") to list 

No usar += le da el TypeError aquí porque solo __iadd__ implementa el comportamiento extendido.

Demo 4: error común: += no genera una nueva lista. Podemos confirmar esto verificando identidades de objeto iguales con el operador is .

 >>> l = [] >>> l_ref = l # another name for l, no data is copied here >>> l += [1, 2, 3] # uses __iadd__, mutates l in-place >>> l is l_ref # confirm that l and l_ref are names for the same object True >>> l [1, 2, 3] >>> l_ref # mutations are seen across all names [1, 2, 3] 

Sin embargo, la syntax l = l + iterable crea una nueva lista.

 >>> l = [] >>> l_ref = l # another name for l, no data is copied here >>> l = l + [1, 2, 3] # uses __add__, builds new list and reassigns name l >>> l is l_ref # confirm that l and l_ref are names for different objects False >>> l [1, 2, 3] >>> l_ref [] 

En algunos casos, esto puede producir errores sutiles, porque += muta la lista original, mientras que
l = l + iterable construye una nueva lista y reasigna el nombre l .

PRIMA

El desafío de Ned Batchelder para encontrar esto en los documentos.

No.

7.2.1. Declaraciones de asignación aumentada :

Una expresión de asignación aumentada como x += 1 puede reescribirse como x = x + 1 para lograr un efecto similar, pero no exactamente igual. En la versión aumentada, x solo se evalúa una vez. Además, cuando sea posible, la operación real se realiza en el lugar, lo que significa que en lugar de crear un nuevo objeto y asignarlo al objective, el objeto antiguo se modifica en su lugar.

Si en el segundo caso, envuelve una lista alrededor de n para evitar errores:

 for n in l: i = i + [n] print(i) 

usted obtiene

 ['table'] 

Así que son operaciones diferentes.