Если вам нужен изменяемый объект, вы должны манипулировать self
и return self
(не новым объектом). Если вы определите __iadd__
с чем-то вроде
def __iadd__(self, other):
self.n += ...
self.d += ...
, функция вернет None
, что и присваивается имени q1
. Если у вас есть другая ссылка на объект, вы увидите, что он был обновлен на месте, но q1
больше не будет ссылаться на него.
Чтобы создать небольшой пример, давайте посмотрите на Fract.__imul__
, который не возвращает self
(поскольку реализация проще, чем __iadd__
):
class Fract:
def __init__(self, x, y):
self.n = x
self.d = y
def __imul__(self, other):
self.n *= other.n
self.d *= other.d
x1 = Fract(1,2)
x2 = x1
y = Fract(1,2)
x1 *= y
После запуска этого кода вы увидите, что x1
теперь привязан к None
, но x2
по-прежнему привязан к исходному экземпляру Fract
, который теперь имеет x2.d == 4
, как и ожидалось.
Так что даже если вы хотите обновить левый операнд в место, __iadd__
и др. по-прежнему необходимо возвращать self
, чтобы имя сохраняло то же значение.
Если вы хотите, чтобы Fract
было неизменным (например, int
или complex
) , вместо этого верните новый объект.
def __imul__(self, other):
return Fract(self.n*other.n, self.d*other.d)