Переопределение "+ =" в Python? (метод __iadd __ ()) - PullRequest
56 голосов
/ 26 июня 2009

Возможно ли переопределить + = в Python?

Ответы [ 4 ]

100 голосов
/ 26 июня 2009

Да, переопределить метод __iadd__. Пример:

def __iadd__(self, other):
    self.number += other.number
    return self    
21 голосов
/ 21 июля 2015

В дополнение к тому, что правильно указано в ответах выше, стоит явно уточнить, что когда __iadd__ переопределяется, операция x += y НЕ заканчивается завершением метода __iadd__.

Вместо этого он заканчивается x = x.__iadd__(y). Другими словами, Python присваивает возвращаемое значение вашей __iadd__ реализации объекту, к которому вы «добавляете», ПОСЛЕ того, как реализация завершается.

Это означает, что можно изменить левую часть операции x += y, чтобы завершить неявный шаг. Подумайте, что может произойти, когда вы добавляете что-то в список:

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

Теперь, если ваша реализация __iadd__ (метод объекта на x[1]) ошибочно или намеренно удаляет первый элемент (x[0]) из начала списка, Python запустит ваш __iadd__ метод) и попытайтесь присвоить его возвращаемое значение x[1]. Который больше не будет существовать (это будет x[0]), в результате ÌndexError.

Или, если ваш __iadd__ вставит что-то в начало x приведенного выше примера, ваш объект будет иметь значение x[2], а не x[1], а то, что раньше было x[0], теперь будет иметь значение x[1] и ему будет присвоено возвращаемое значение вызова __iadd__.

Если человек не понимает, что происходит, возникающие ошибки могут стать кошмаром для исправления.

12 голосов
/ 26 июня 2009

В дополнение к перегрузке __iadd__ (не забывайте возвращать себя!), Вы также можете откатиться на __add__, так как x + = y будет работать как x = x + y.(Это одна из ловушек оператора + =.)

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

Даже отключает экспертов :

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

x = Resource()
y = Resource()

Какие значения вы ожидаете x.id, y.id и Resource.class_counter иметь?

5 голосов
/ 26 июня 2009

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

Например, чтобы выполнить инструкцию x + = y, где x - это экземпляр класс, который имеет метод __iadd __ (), x .__ iadd __ (y) называется.

...