Перегрузка оператора в Python: обработка различных типов и порядок параметров



Answers

Существуют специальные методы для обратных операций :

  • __rmul__ для обратной __mul__
  • и __radd__ для __add__ ,
  • ...

Они NotImplemented когда оператор левой руки возвращает NotImplemented для нормальной работы (поэтому сначала операция 2 + vector_instance попытается: (2).__add__(vector_instance) но если это возвращает NotImplemented тогда vector_instance.__radd__(2) ).

Однако я бы не использовал проверки isinstance в арифметических специальных методах, что приведет к много повторения кода.

Фактически вы можете создать специальный случай в __init__ и реализовать преобразование из скаляров в Vector :

class Vector(object):
    def __init__(self, x, y=None, z=None):
        if y is None and z is None:
            if isinstance(x, Vector):
                self.x, self.y, self.z = x.x, x.y, x.z
            else:
                self.x, self.y, self.z = x, x, x
        elif y is None or z is None:
            raise ValueError('Either x, y and z must be given or only x')
        else:
            self.x, self.y, self.z = x, y, z

    def __mul__(self, other):
        other = Vector(other)
        return Vector(self.x*other.x, self.y*other.y, self.z*other.z)

    __rmul__ = __mul__   # commutative operation

    def __sub__(self, other):
        other = Vector(other)
        return Vector(self.x-other.x, self.y-other.y, self.z-other.z)

    def __rsub__(self, other):   # not commutative operation
        other = Vector(other)
        return other - self

    def __repr__(self):
        return 'Vector({self.x}, {self.y}, {self.z})'.format(self=self)

Это должно работать так, как ожидалось:

>>> 2 - Vector(1, 2, 3)
Vector(1, 0, -1)

>>> Vector(1, 2, 3) - 2
Vector(-1, 0, 1)

>>> Vector(1, 2, 3) * 2
Vector(2, 4, 6)

>>> 2 * Vector(1, 2, 3)
Vector(2, 4, 6)

Обратите внимание, что это был быстрый и грязный проект (который может иметь несколько ошибок). Я просто хотел представить «общую идею» о том, как ее можно было бы решить без специального обтекания типа в каждой арифметической операции.

Question

На этот вопрос уже есть ответ:

У меня есть простой класс, который помогает с математическими операциями над векторами (т.е. списками чисел). Мой Vector можно умножить на другие экземпляры Vector или скаляр ( float или int ).

В других, более строго типизированных языках я бы создал метод для умножения двух vector s и отдельный метод для умножения vector by и int / float . Я все еще довольно новичок в Python и не знаю, как это реализовать. Единственный способ, которым я могу это сделать, - переопределить __mul__() и проверить входящий параметр:

class Vector(object):
  ...
 def __mul__(self, rhs):
  if isinstance(rhs, Vector):
     ...
  if isinstance(rhs, int) or isinstance(rhs, float):
    ...

Даже если я сделаю так, я буду вынужден умножить Vector на такой скаляр:

v = Vector([1,2,3])

result = v * 7

Что делать, если я хотел бы изменить порядок операндов в умножении?

result = 7 * v

Каков правильный способ сделать это в Python?




Links