web-dev-qa-db-fra.com

Remplacer "+ =" en Python? (méthode __iadd __ ())

Est-il possible de remplacer + = en Python?

59
Evan Fosmark

Oui, remplacez le __iadd__ méthode. Exemple:

def __iadd__(self, other):
    self.number += other.number
    return self    
104
John Kugelman

En plus de ce qui est correctement donné dans les réponses ci-dessus, il convient de préciser explicitement que lorsque __iadd__ Est remplacé, l'opération x += y Ne se termine PAS avec la fin de la méthode __iadd__.

Au lieu de cela, il se termine par x = x.__iadd__(y). En d'autres termes, Python affecte la valeur de retour de votre implémentation __iadd__ À l'objet que vous "ajoutez", APRÈS la fin de l'implémentation.

Cela signifie qu'il est possible de muter le côté gauche de l'opération x += y Afin que l'étape implicite finale échoue. Considérez ce qui peut se produire lorsque vous ajoutez quelque chose à l'intérieur d'une liste:

>>> x[1] += y # x has two items

Maintenant, si votre implémentation __iadd__ (Une méthode d'un objet à x[1]) Supprime par erreur ou exprès le premier élément (x[0]) Du début de la liste, Python exécutera alors votre méthode __iadd__) Et essayera d'attribuer sa valeur de retour à x[1]. Qui n'existera plus (il sera à x[0]), Résultant en un ÌndexError.

Ou, si votre __iadd__ Insère quelque chose au début de x de l'exemple ci-dessus, votre objet sera à x[2], Pas à x[1], Et tout ce qui était antérieur à x[0] sera désormais à x[1] et se verra attribuer la valeur de retour de l'invocation __iadd__.

À moins que l'on comprenne ce qui se passe, les bogues qui en résultent peuvent être un cauchemar à corriger.

21
Petri

En plus de surcharger __iadd__ (n'oubliez pas de retourner vous-même!), vous pouvez également recourir à __add__, car x + = y fonctionnera comme x = x + y. (C'est l'un des pièges de l'opérateur + =.)

>>> class A(object):
...   def __init__(self, x):
...     self.x = x
...   def __add__(self, other):
...     return A(self.x + other.x)
>>> a = A(42)
>>> b = A(3)
>>> print a.x, b.x
42 3
>>> old_id = id(a)
>>> a += b
>>> print a.x
45
>>> print old_id == id(a)
False

Il a même voyage des experts :

class Resource(object):
  class_counter = 0
  def __init__(self):
    self.id = self.class_counter
    self.class_counter += 1

x = Resource()
y = Resource()

Quelles valeurs attendez-vous x.id, y.id, et Resource.class_counter avoir?

12
Roger Pate

http://docs.python.org/reference/datamodel.html#emulating-numeric-types

Par exemple, pour exécuter l'instruction x + = y, où x est une instance d'une classe qui a une méthode __iadd __ (), x .__ iadd __ (y) est appelée.

5
Unknown