Перегрузка оператора в python с объектом в правой части оператора

#python

#питон #перегрузка оператора

Вопрос:

Недавно я узнал о перегрузке операторов в python, и я хотел бы знать, возможно ли следующее.

Рассмотрим следующий гипотетический / надуманный класс.

 class My_Num(object):
    def __init__(self, val):
        self.val = val
    def __add__(self, other_num):
        if isinstance(other_num, My_Num):
            return self.val   other_num.val
        else:
            return self.val   other_num
 

Я знаю, что так, как написано выше, я могу делать такие вещи

 n1 = My_Num(1)
n2 = My_Num(2)
n3 = 3
print n1   n2
print n1   n3
 

и они будут работать так, как ожидалось. Я также знаю, что в том виде, в котором он сейчас написан, я не могу этого сделать

 n1 = My_Num(1)
n2 = 2
print 2   n1
 

Есть ли что-нибудь вокруг этого? Я знаю, что этот пример надуманный, но у меня есть приложение, в котором было бы очень полезно, если бы при перегрузке оператора класс, для которого я определяю оператор, мог появиться в правой части operator . Возможно ли это в python?

Ответ №1:

ДА. Например, есть __radd__ . Кроме того, нет ни одного для __le__() , __ge__() , и т.д., Но, как справедливо замечает Джоэл Корнетт, если вы определяете только __lt__ , a > b вызывает __lt__ функцию b , которая обеспечивает обходной путь.

 >>> class My_Num(object):
...     def __init__(self, val):
...         self.val = val
...     def __radd__(self, other_num):
...         if isinstance(other_num, My_Num):
...             return self.val   other_num.val
...         else:
...             return self.val   other_num
... 
>>> n1 = My_Num(1)
>>> n2 = 3
>>> 
>>> print n2   n1
4
>>> print n1   n2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for  : 'My_Num' and 'int'
 

Обратите внимание, что, по крайней мере, в некоторых случаях разумно сделать что-то вроде этого:

 >>> class My_Num(object):
...     def __init__(self, val):
...         self.val = val
...     def __add__(self, other_num):
...         if isinstance(other_num, My_Num):
...             return self.val   other_num.val
...         else:
...             return self.val   other_num
...     __radd__ = __add__
 

Комментарии:

1. Спасибо. Является ли radd единственным, который позволяет это? Конкретными операторами, которые мне нужно перегрузить для моего приложения, являются операторы >> и << . Мне просто не повезло, если я хочу сделать это для этих операторов?

2. Нет. Вы нажали на ссылку? Есть __rrshift__ , и так далее.

3. В ограниченной степени можно корректно сравнивать, контролируя, какие операторы определены для каждого класса. Например, если A и B имеют только lt . A<B и B>A вызовут метод, принадлежащий младшему концу.

4. Есть ли какой-либо способ изменить ассоциативность оператора? Например, могу ли я сделать >> оператор правильным ассоциативным?

5. @martega, в этом я сильно сомневаюсь. Но я на самом деле не знаю.

Ответ №2:

Вы должны перегрузить __radd__ метод (добавление с правой стороны). Ваша функция должна выглядеть практически так же, как и ваш __add__ метод, например:

 def __radd__(self, other):
     return self.val   other.val