Переопределение магических методов стандартных классов int и float
ㅤㅤ У меня есть класс A с магическими методами сложения, вычитания и так далее. Эти магические методы класса А преобразуют передаваемый other (который может быть int или float) в экземпляр класса A (для вычислений). И я спокойно могу складывать A с переданным other, какого типа он бы не был (в противном случае - эксепшэн)
## Рабочий класс с определёнными магическими методами
class A:
## Магический метод, вызываемый при str(A())
def __str__(self):
return '"%s"' % (self.s)
## Магический метод сложения (+)
def __add__(self, other):
# other должен быть преобразован в тип A по-любому, иначе эксепшн
if not isinstance(other,A):
other=A(other)
return A(self.s+other.s) # Возврат нового экземпляра A, после операции сложения двух экземпляров
## Класс инициализации
def __init__(self,s:float):
# Создание нужных атрибутов...
self.s=float(s)
# Запуск скрипта, если это самостоятельный запуск
if __name__=='__main__':
r1=A(7) # Экземпляр класса A
r2=A(4) # Экземпляр класса A
r3=10 # Тип int
print(r1+r2) # Напечатается "11.0"
print(r2+r3) # Напечатается "14.0" (этот int преобразовался в экземпляр класса A в вызванном методе __add__ класса A)
print(r3+r2) # Эксепшэн TypeError: unsupported operand type(s) for +: 'int' and 'A'
ㅤㅤ Однако, есть проблема. я не могу сложить int с A, так как вызывается __add__ класса int. И выдает ошибку. Пробовал переопределить поведение таким образом, чтобы принудительно складывать A с int при попытке сложить int с A:
# Переопределение поведения класса int при вызове __add__
class int(int):
def __add__(self, x:A):
return x+self
m1=A(4) # Экземпляр класса A
m2=int(10)
m3=10
print(m2+m1) # Печатает "14.0"
print(m3+m1) # TypeError: unsupported operand type(s) for +: 'int' and 'A'
ㅤㅤ Однако поведение странное: если после такого переопределения инициализировать int(10), всё будет хорошо, но просто написав 10, будет снова вызвано исключение.
ㅤㅤ Возможно ли корректно добавлять магические методы в стандартные классы? Чтобы было возможным складывать int с A или float с A и любой другой встроенный класс c A. Или какое решение будет более рациональным?
Ответы (1 шт):
Используйте __radd__:
class A:
def __str__(self):
return '"%s"' % (self.s)
def __add__(self, other):
if not isinstance(other,A):
other=A(other)
return A(self.s+other.s)
# Выполняется, если экземпляр класса является вторым слагаемым
def __radd__(self, other):
return self + other
def __init__(self,s:float):
self.s=float(s)
r1=A(7)
r2=A(4)
r3=10
print(r1+r2)
print(r2+r3)
print(r3+r2) # И никакого экзепшна!
Если у первого слагаемого нет своего __add__, а у второго слагаемого есть __radd__, то выполнится именно он.