Python problema de asignación aumentada

Me encontré con algo interesante sobre la asignación aumentada de Python +=

Parece que la conversión automática del tipo de datos no siempre se realiza para a += b si a es un tipo de datos ‘más simple’, mientras que a = a + b parece funcionar siempre

Casos donde se realiza la conversión.

 a = 1 b = 1j a = 1 b = 0.5 

caso en el que la conversión no se realiza

 from numpy import array a = array([0, 0 ,0]) b = array([0, 0, 1j]) 

después de a += b , a permanece como matriz entera, en lugar de matriz compleja

Solía ​​pensar que a += b es lo mismo que a = a + b , ¿cuál es la diferencia entre ellos en la implementación subyacente?

Para el operador + , Python define tres métodos “especiales” que un objeto puede implementar:

  • __add__ : agrega dos elementos (operador + ). Cuando haces a + b , el método __add__ de a se llama con b como argumento.
  • __radd__ : añadido reflejado; para a + b , el método __radd__ de b se llama con a como una instancia. Esto solo se usa cuando a no sabe cómo hacer la adición y los dos objetos son de tipos diferentes.
  • __iadd__ : agregar en el lugar; se utiliza para a += b donde el resultado se asigna de nuevo a la variable izquierda. Esto se proporciona por separado porque podría ser posible implementarlo de una manera más eficiente. Por ejemplo, si a es una lista, entonces a += b es lo mismo que a.extend(b) . Sin embargo, en el caso de c = a + b , debe hacer una copia de a antes de extenderla, ya que a no debe modificarse en este caso. Tenga en cuenta que si no implementa __iadd__ , Python simplemente llamará a __add__ en __add__ lugar.

Por lo tanto, dado que estas diferentes operaciones se implementan con métodos separados, es posible (pero generalmente una mala práctica) implementarlas para que hagan cosas totalmente diferentes, o quizás en este caso, solo cosas ligeramente diferentes.

Otros han deducido que estás usando NumPy y explicado su comportamiento. Sin embargo, usted preguntó acerca de la implementación subyacente. Esperemos que ahora vea por qué a veces ocurre que a += b no es lo mismo que a = a + b . Por cierto, un trío similar de métodos también se puede implementar para otras operaciones. Consulte esta página para obtener una lista de todos los métodos in situ admitidos.

Si la array es numpy.array (en realidad no especifica), entonces el problema que está ocurriendo es porque estas matrices no pueden cambiar su tipo. Cuando crea la matriz sin un especificador de tipo, adivina un tipo. Si luego intenta realizar una operación que el tipo no admite (como agregarlo a un tipo con un dominio más grande, como complejo), Numpy sabe realizar el cálculo, pero también sabe que el resultado solo se puede almacenar en el tipo con el dominio más grande. Se queja (en mi máquina, de todos modos, la primera vez que hago una tarea de este tipo) que el resultado no encaja. Cuando haces una adición regular, se debe hacer una nueva matriz en cualquier caso, y numpy le da el tipo correcto.

 >>> a=numpy.array([1]) >>> a.dtype dtype('int32') >>> b=numpy.array([1+1j]) >>> b.dtype dtype('complex128') >>> a+b array([ 2.+1.j]) >>> (a+b).dtype dtype('complex128') >>> a+=b >>> a array([2]) >>> a.dtype dtype('int32') >>> 

La diferencia entre a = a + b y a += b es que la última adición, siempre que sea posible, se hará “in situ”, es decir, cambiando el objeto a . Puedes ver esto fácilmente con listas.

 a = b = [1, 2] a += [3] print b # [1, 2, 3] a = b = [1, 2] a = a + [3] print b # [1, 2] 

La respuesta de Rafe Kettler es correcta, pero parece que has logrado obtener a = [0,0,0] después de agregarla a b (según tu publicación).

Bueno, si estás usando numpy o scipy (digo esto porque veo una array y me pregunto qué matriz se está creando aquí), entonces esto es “normal”, e incluso debería mostrar una advertencia:

ComplexWarning: Convertir valores complejos en reales descarta la parte imaginaria