2010-08-10 8 views
8

Envisagez la session suivante. Comment les différences sont-elles expliquées? Je pensais que a += b est un sucre syntactique de (et donc équivalent à) a = a + b. Évidemment, j'ai tort.Traitement des données par référence ou par valeur dans 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.]] 

Merci

Répondre

15

En utilisant les résultats + de l'opérateur dans un appel à la méthode spéciale __add__ qui devrait créer un nouvel objet et ne devrait pas modifier l'original. En revanche, l'utilisation de l'opérateur += entraîne un appel à __iadd__ qui devrait modifier l'objet si possible plutôt que de créer un nouvel objet.

__add__

Ces méthodes sont appelées à mettre en œuvre les opérations arithmétiques binaires (+, -, *, //,%, divmod(), pow(), **, < <,> >, &, ^, |). Par exemple, pour évaluer l'expression x + y, où x est une instance d'une classe qui a une méthode __add __(), x .__ add __ (y) est appelée.

__iadd__

Ces méthodes sont appelés à mettre en œuvre les missions arithmétiques (+ = augmentée, - =, * =,/=, // =,% =, ** =, < < =,> > =, & =,^=, | =). Ces méthodes devraient essayer de faire l'opération sur place (en modifiant soi-même) et retourner le résultat (qui pourrait être, mais ne doit pas être, soi-même).

Bien sûr, il est possible de mettre en œuvre __add__ et __iadd__ d'avoir un autre comportement si vous voulez, mais ce que vous observez est la manière standard et recommandée. Et, oui, c'est un peu surprenant la première fois que vous le voyez.

+0

est cette différence spécifique de python ou est-il une caractéristique commune de '+' 'opérateurs vs + =' dans les langages de programmation? –

+0

@bgbg: Ceci est spécifique à Python. En C# par exemple 'a = a + b' est presque équivalent à' a + = b'. –

+0

Aide si vous considérez + = comme opération d'incrémentation pas raccourcie pour ajouter des valeurs. –

7

Vous n'êtes pas mal, parfois a += b est vraiment sucre syntaxique pour a = a + b, mais parfois ce n'est pas, ce qui est l'une des fonctionnalités les plus déroutants de Python - voir this similar question pour une discussion plus approfondie.

L'opérateur + appelle la méthode spéciale __add__, et l'opérateur +=tente de appellent la en place __iadd__ méthode spéciale, mais je pense qu'il vaut la peine de l'expansion cas où __iadd__ n'est pas défini.

Si l'opérateur in-place n'est pas défini, par exemple pour les types immuables tels que les chaînes et les entiers, alors __add__ est appelé à la place. Donc, pour ces types a += b est vraiment sucre syntaxique pour a = a + b. Cette classe de jouets illustre le point:

>>> 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__) 

C'est le comportement que vous devriez attendre de n'importe quel type qui est immuable.Bien que cela puisse prêter à confusion, l'alternative serait d'interdire += sur les types immuables ce qui serait regrettable car cela signifierait que vous ne pourriez pas l'utiliser sur des chaînes ou des nombres entiers!

Pour un autre exemple, cela conduit à une différence entre les listes et les tuples, les deux qui soutiennent +=, mais les listes ne peuvent être modifiés:

>>> 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] 

Bien sûr, la même chose pour tous les autres en place opérateurs, -=, *=, //=, %=, etc.

Questions connexes