#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