2010-08-10 21 views
8

Considere la siguiente sesión. ¿Cómo se explican las diferencias? Pensé que a += b es un azúcar sintáctico de (y por lo tanto equivalente a) a = a + b. Obviamente estoy equivocado.Procesamiento de datos por referencia o por valor en python

>>> import numpy as np 
>>> a = np.arange(24.).reshape(4,6) 
>>> print a 
[[ 0. 1. 2. 3. 4. 5.] 
[ 6. 7. 8. 9. 10. 11.] 
[ 12. 13. 14. 15. 16. 17.] 
[ 18. 19. 20. 21. 22. 23.]] 
>>> for line in a: 
...  line += 100 
... 
>>> print a #a has been changed 
[[ 100. 101. 102. 103. 104. 105.] 
[ 106. 107. 108. 109. 110. 111.] 
[ 112. 113. 114. 115. 116. 117.] 
[ 118. 119. 120. 121. 122. 123.]] 
>>> 
>>> for line in a: 
...  line = line + 999 
... 
>>> print a #a hasn't been changed 
[[ 100. 101. 102. 103. 104. 105.] 
[ 106. 107. 108. 109. 110. 111.] 
[ 112. 113. 114. 115. 116. 117.] 
[ 118. 119. 120. 121. 122. 123.]] 

Gracias

Respuesta

15

Utilizando los resultados + operador en una llamada al método especial __add__ que debe crear un nuevo objeto y no debe modificar el original.

Por otro lado, usar el operador += da como resultado una llamada al __iadd__ que debe modificar el objeto si es posible en lugar de crear un nuevo objeto.

__add__

Estos métodos son llamados a poner en práctica las operaciones aritméticas binarias (+, -, *, //,%, DIVMOD(), pow(), **, < <,> >, &, ^, |). Por ejemplo, para evaluar la expresión x + y, donde x es una instancia de una clase que tiene un método __add __(), se llama x .__ add __ (y).

__iadd__

Estos métodos están llamados a poner en práctica las asignaciones aritméticas aumentada (+ =, - =, * =,/=, // =,% =, ** =, < < =,> > =, & =,^=, | =). Estos métodos deben intentar realizar la operación in situ (auto modificándose) y devolver el resultado (que podría ser, pero no tiene que ser, uno mismo).

Por supuesto, es posible implementar __add__ y __iadd__ que tienen algún otro comportamiento si se quería, pero lo que se observa es la forma estándar y recomendado. Y, sí, es un poco sorprendente la primera vez que lo ves.

+0

es esta diferencia específica de pitón o es una característica común de '+' 'vs + =' operadores en lenguajes de programación? –

+0

@bgbg: Esto es específico de Python. En C#, por ejemplo, 'a = a + b' es casi equivalente a' a + = b'. –

+0

Ayuda si considera que + = como operación de incremento no es un atajo para agregar valores. –

7

Usted no está mal, a veces a += b realmente es el azúcar sintáctica para a = a + b, pero a veces no lo es, que es una de las características más confusos de Python - ver this similar question para más discusión.

El operador + llama al método especial __add__, y los += operador intenta llamada al método especial en el lugar __iadd__, pero creo que vale la pena la expansión en el caso en que __iadd__ no está definido.

Si el operador in situ no está definido, por ejemplo para tipos inmutables como cadenas y enteros, entonces se llama a __add__. Por lo tanto, para estos tipos a += b realmente es azúcar sintáctica para a = a + b. Esta clase de juguete ilustra el punto:

>>> class A(object): 
...  def __add__(self, other): 
...   print "In __add__ (not __iadd__)" 
...   return A() 
... 
>>> a = A() 
>>> a = a + 1 
In __add__ (not __iadd__) 
>>> a += 1 
In __add__ (not __iadd__) 

Este es el comportamiento que debe esperar de cualquier tipo que sea inmutable.Si bien esto puede ser confuso, la alternativa sería no permitir += en tipos inmutables, lo que sería desafortunado ya que eso significaría que no podrías usarlo en cadenas o enteros.

Para otro ejemplo, esto conduce a una diferencia entre las listas y tuplas, ambos de los cuales apoyan +=, pero sólo las listas pueden ser modificados:

>>> a = (1, 2) 
>>> b = a 
>>> b += (3, 4) # b = b + (3, 4) (creates new tuple, doesn't modify) 
>>> a 
(1, 2) 

>>> a = [1, 2] 
>>> b = a 
>>> b += [3, 4] # calls __iadd___ so modifies b (and so a also) 
>>> a 
[1, 2, 3, 4] 

Por supuesto, el mismo ocurre con todos los demás en el lugar operadores, -=, *=, //=, %=, etc.

Cuestiones relacionadas