Изменение порядка операций для методов __add__, __mul__ и т. Д. В пользовательском классе

У меня есть векторный класс:

class Vector: def __init__(self, x, y): self.x, self.y = x, y def __str__(self): return '(%s,%s)' % (self.x, self.y) def __add__(self, n): if isinstance(n, (int, long, float)): return Vector(self.x+n, self.y+n) elif isinstance(n, Vector): return Vector(self.x+nx, self.y+ny) 

который отлично работает, т.е. я могу написать:

 a = Vector(1,2) print(a + 1) # prints (2,3) 

Однако, если порядок операций отменен, то он не выполняется:

 a = Vector(1,2) print(1 + a) # raises TypeError: unsupported operand type(s) # for +: 'int' and 'instance' 

Я понимаю ошибку: добавление объекта int объекту Vector не определено, потому что я не определил его в классе int . Есть ли способ обойти это без определения его в классе int (или родительском int )?

Вы также должны определить __radd__

Некоторые операции не обязательно оценивают как a + b == b + a, поэтому Python определяет методы add и radd .

Объясняя себя лучше: он поддерживает тот факт, что «int» не определяет операцию + с экземплярами class Vector как часть операции. Поэтому вектор + 1 не совпадает с вектором 1 +.

Когда Python пытается увидеть, что может сделать метод 1.__add__ , возникает исключение. И Python идет и ищет операцию Vector.__radd__ чтобы попытаться ее завершить.

В случае OP оценка истинна и достаточна с __radd__ = __add__

 class Vector(object): def __init__(self, x, y): self.x, self.y = x, y def __str__(self): return '(%s,%s)' % (self.x, self.y) def __add__(self, n): if isinstance(n, (int, long, float)): return Vector(self.x+n, self.y+n) elif isinstance(n, Vector): return Vector(self.x+nx, self.y+ny) __radd__ = __add__ a = Vector(1, 2) print(1 + a) 

Какие результаты:

 (2,3) 

То же самое относится ко всем числовым операциям.

Когда вы говорите x + y , Python вызывает x.__add__(y) . Если x не реализует __add__ (или этот метод возвращает NotImplemented ), Python пытается вызвать y.__radd__(x) в качестве резервной копии.

Таким образом, все, что вам нужно сделать, это определить метод __radd__() в вашем классе Vector, а 1 + y будет работать так, как вы ожидали.

Примечание: вам нужно было бы сделать подобное для других операций, например, реализовать __mul__() и __rmul__() пару и т. Д.

Вы также можете посмотреть на этот вопрос , он объясняет тот же принцип более подробно.

Обновление. В зависимости от вашего __iadd__() использования вы также можете реализовать метод __iadd__() (и его кузены), чтобы переопределить оператор += .

Например, если вы скажете y += 1 ( y – экземпляр Vector здесь), вы можете захотеть изменить сам экземпляр y и не возвращать в результате новый экземпляр Vector , какой метод в настоящее время выполняет ваш __add__() ,