Вопрос по python – Переопределение «+ =» в Python? (метод __iadd __ ())

51

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

да, но использование поиска по сайту: + = python не дает результатов. ставить кавычки вокруг "+ =" дает результаты, но в основном не имеет значения, судя по заголовкам. нашел это через поиск Google, хотя. jcomeau_ictx
Точная копияstackoverflow.com/questions/728361/… Scott Griffiths

Ваш Ответ

4   ответа
91

__iadd__ метод. Пример:

def __iadd__(self, other):
    self.number += other.number
    return self    
@ScottGriffiths То же самое верно для__imul__?
@ScottGriffiths, так вы говорите, что если вы реализовали__add__ Вы не обязательно должны выполнять__iadd__? Я прочитал дубликат вопроса, который вы связали, но я просто запутался, потому что я не понимаю, почему вы должны реализовать__add__ так что он мутирует объект
@ScottGriffiths означает «спросить», вам не обязательно реализовывать__iadd__ to use +=? & Quot;
Вы не должны реализовывать__iadd__ если ваш класс представляет неизменные объекты. В этом случае просто реализовать__add__ который будет использоваться для переопределения+= вместо. Например, вы можете использовать+= для неизменяемых типов, таких как строки и целые числа, которые нельзя сделать с помощью__iadd__.
@JosieThompson: если вы не реализуете__iadd__ тогда он будет использовать__add__ если доступно, что обычно просто отлично. Так что в этом случаеa += b будет эквивалентноa = a + b, который присваивает новое значениеa вместо сменыa сам. Имея отдельный__iadd__ как правило, хорошая оптимизация, а не то, что вам нужно использовать+= оператор.
16

что правильно указано в ответах выше, стоит четко указать, что, когда__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__ метод) & amp; попытаться присвоить его возвращаемое значениеx[1], Который больше не будет существовать (это будет вx[0]), в результате чегоÌndexError.

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

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

12

__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 иметь?

Ваш второй пример не имеет ничего общего с iadd или + =. Тот же самый результат происходит, если вы используете self.class_counter = self.class_counter + 1 Это просто проблема с областью видимости, использующая self, когда должен использоваться Resource.
Это пример того, как использование + = может привести к проблемам. Если вы перегруженыiaddзатем вы открываете к этому пользователей вашего класса (включая себя), и, по крайней мере, вы должны знать, что проблема существует заранее.
@FogleBird: это гоча, потому чтоfoo += bar может означать "изменить существующий объект, которыйfoo относится к & quot; или & quot; назначитьfoo к объекту, полученному в результате выраженияfoo + bar& Quot ;. И что происходит, зависит от того,foo имеет__iadd__ метод.
5

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

For instance, to execute the statement x += y, where x is an instance of a class that has an __iadd__() method, x.__iadd__(y) is called.

Похожие вопросы