2010-12-07 48 views
14

me encontré con algo interesante sobre la tarea pitón aumentada +=Python aumentada problema de asignación

parece ser el tipo de datos automática de conversión no siempre se hace para a += b si a es un tipo de datos 'simple', mientras que a = a + b parece el trabajo siempre

los casos en que la conversión se realiza

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 a += b, a permanece como matriz de enteros, en lugar de matriz compleja

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

+0

¿a qué se refiere 'array' en su ejemplo? ¿Eso es del módulo integrado 'array'? si es así, su ejemplo ni siquiera funciona, ya que no hay código de tipo ... – SingleNegationElimination

+0

'a = array ([0, 0, 0])' y 'b = array ([0, 0, 1j])' don ' Trabajar con la clase 'array' en el módulo del mismo nombre. Ambos carecen de un argumento inicial * typecode *. Y, AFAIK, la clase no admite números complejos ni '+ =' asignación aumentada. Así que no entiendo lo que estás preguntando aquí. – martineau

+0

@martineau Vea mi comentario sobre la respuesta de Rafe (ahora eliminada) haciendo referencia a esta pregunta de NumPy: http://www.scipy.org/FAQ#head-1ed851e9aff803d41d3cded8657b2b15a888ebd5 – ACoolie

Respuesta

15

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

  • __add__: añade dos elementos (+ operador). Cuando lo haga a + b, se llama al método __add__ de a con b como argumento.
  • __radd__: reflejado agregar; para a + b, se llama al método __radd__ de b con a como instancia. Esto solo se usa cuando a no sabe cómo hacer el agregado y los dos objetos son de tipos diferentes.
  • __iadd__: in-place add; usado 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á al __add__.

Así que ya que estas operaciones se implementan diferentes con distintos métodos, es posible (pero por lo general una mala práctica) para ponerlas en práctica de manera que hacen cosas totalmente diferentes, o tal vez en este caso, sólo ligeramente cosas diferentes.

Otros han deducido que está usando NumPy y explicaron su comportamiento. Sin embargo, preguntaste sobre la implementación subyacente. Esperemos que ahora vea por qué a veces es el caso que a += b no es lo mismo que a = a + b. Por cierto, un trío similar de métodos también puede implementarse para otras operaciones. Consulte this page para obtener una lista de todos los métodos in situ compatibles.

+1

Debo notar que en el ejemplo que di para las listas, 'a + = b' en realidad tiene resultados diferentes de' a = a + b'. Si 'a' se conoce con otro nombre, ese otro nombre" verá "la lista extendida después de' a + = b' pero no después de 'a = a + b'. – kindall

0

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

Bueno, si usted está utilizando numpy o scipy (lo digo porque veo array y pregunto lo que se está creando gama aquí), entonces esto es "normal", e incluso debería plantear una advertencia:

ComplexWarning: fundición valores complejos a los descartes reales la parte imaginaria

1

la diferencia entre a = a + b y a += b está, que esta última adición será, siempre que sea posible, hace “in-place” que significa 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] 
+0

Sí, y en el caso de las matrices numpy, eso significa mantener el tipo de 'a' igual, por lo que los números complejos no se representarán. – tkerwin

7

numpy.array Si es array (realidad no se especifica), entonces el problema que está sucediendo 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 ese tipo no admite (como agregarla 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 tal tarea) de 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') 
>>>