Помогите с калькулятором комплексных чисел Python
Пишу калькулятор комплексных чисел, реализующий основные математические операции. Получилось так, вроде все работает:
class MathComplex:
def __init__(self, real=0, imag=0):
self.real = real
self.imag = imag
def __abs__(self):
return MathComplex((self.real**2 + self.imag**2)**0.5)
def __repr__(self):
real = self.real if self.real != 0 else ""
imag = "" if self.imag == 0 or abs(self.imag) == 1 else abs(self.imag)
i_sign = "i" if self.imag != 0 else ""
sign = "+" if self.imag > 0 and self.real != 0 else "-" if self.imag < 0 else ""
return '{}{}{}{}'.format(real, sign, imag,i_sign)
def __add__(self, other):
return MathComplex(self.real + other.real, self.imag + other.imag)
def __sub__(self, other):
return MathComplex(self.real - other.real, self.imag - other.imag)
def __mul__(self, other):
return MathComplex(self.real*other.real - self.imag*other.imag, self.real*other.imag + self.imag*other.real)
def __truediv__(self, other):
real = (self.real*other.real + self.imag*other.imag) / (other.real**2 + other.imag**2)
imag = (self.imag*other.real - self.real*other.imag) / (other.real**2 + other.imag**2)
return MathComplex(real, imag)
def __neg__(self):
return MathComplex(self.imag)
def __eq__(self, other):
if self.real == other.real and self.imag == other.imag:
return True
else:
return False
def __round__(self, n):
return MathComplex(round(self.real, n), round(self.imag, n))
def conjugate(self):
self.imag = - self.imag
return MathComplex()
Запинка в следующем пункте:
В математике у нас определены выражения вида (1+5i) + 42. Если перевести это на язык объектов питона, то мы к комплексному числу прибавляем объект int. Нужно отнаследовать класс ExtendedComplex и реализовать в нем соответствующие специальные методы, чтобы арифметические операции выполнялись еще и с операндами типа int/float. Немного подробнее: если а - объект любого из классов (int, float, ExtendedComplex), x - экземпляр ExtendedComplex, то должны выполняться оба выражения x + a и a + x.
Имею следующие мысли:
class ExtendedComplex(MathComplex):
def __add__(self, other):
if isinstance(other, (int, float)):
return MathComplex(self.real + other, self.imag)
def __radd__(self, other):
pass
Не понимаю как написать код с __radd__ . Через переменную-ошибку как-то или иначе... Сам синтаксис не понимаю как реализуется.
Спрашиваю для одной операции, понятно что остальные условно по аналогии пойдут.
Пожалуйста, не отправляйте меня в интернет и вот сюда, мне не помогло.
Ответы (3 шт):
Для реализации метода radd в классе ExtendedComplex нужно просто вернуть результат сложения объекта other и экземпляра ExtendedComplex. class ExtendedComplex(MathComplex):
def __add__(self, other):
if isinstance(other, (int, float)):
return MathComplex(self.real + other, self.imag)
def __radd__(self, other):
return self.__add__(other)
Определяете radd, который будет вызван в случае, если слева от оператора + находится объект типа, отличного от MathComplex (т.е. int или float). Внутри метода radd мы просто вызываем метод add и передаем ему аргументы в обратном порядке, т.е. сначала other, а затем self.
Мне не совсем понятно с какой целью вы делаете ещё один класс наследник, вы реалезуете класс для работы с комплексными числами, так зачем его дробить на несколько классов?
Что касается вашего вопроса с перегрузкой оператора __radd__, всё предельно просто:
class ExtendedComplex(MathComplex):
def __add__(self, other):
if isinstance(other, (int, float)):
return MathComplex(self.real + other, self.imag)
def __radd__(self, other):
return self.__add__(other)
В случае если вы уже реализовали метод __add__, то, дабы не дублировать код несколько раз мы можем просто вызвать его, передав наши параметры, ведь в аргументе other всегда будет число, которое мы хотим прибавить к числу, у которого вызывается метод __add__ или __radd__ тобишь self. Получилось немного запутанно, попробую пояснить на примере:
a + b
Эта запись будет эквивалентна следующей:
a.__add__(b)
Если ещё точнее, то у экземпляра объекта a мы вызываем метод __add__ и передаём в качестве параметра b. Следовательно, наш a внутри метода __add__ будет представлен как self, а b т.к. передавался в качестве параметров будет представлен как other. Представим следующий код:
a = ExtendedComplex(140, 2)
a + 7
Тут всё следует примеру выше. У экземпляра a вызывается метод __add__ и передаётся в качестве аргумента 7. Но что если...
a = ExtendedComplex(140, 2)
7 + a
7 является экземпляром класса int, но т.к. он является системным классом он не знает как себя вести с экземпляром класса ExtendedComplex при сложении. Тут нам приходит на помощь метод __radd__. Если попытка вызова метода __add__ у класса int не увенчалась успехом, то Python идёт в класс ExtendedComplex и пытается вызвать у него метод __radd__. Тобишь a.__radd__(7), ничего не напоминает?) Перегрузка оператора __radd__ необходима для правильного выполнения операции сложения, когда объект класса ExtendedComplex находится вторым аргументом, а не первым.
В итоге получилось вот так с учетом того что посоветовали, одним классом и с магическими методами:
class MathComplex:
def __init__(self, real=0, imag=0):
self.real = real
self.imag = imag
def __abs__(self):
return MathComplex((self.real**2 + self.imag**2)**0.5)
if isinstance(self, (int, float)):
return(abs(self))
def __repr__(self):
real = self.real if self.real != 0 else ""
imag = "" if self.imag == 0 or abs(self.imag) == 1 else abs(self.imag)
i_sign = "i" if self.imag != 0 else ""
sign = "+" if self.imag > 0 and self.real != 0 else "-" if self.imag < 0 else ""
return '{}{}{}{}'.format(real, sign, imag,i_sign)
def __add__(self, other):
return MathComplex(self.real + other.real, self.imag + other.imag)
if isinstance(other, (int, float)):
return MathComplex(self.real + other, self.imag)
def __radd__(self, other):
return self.__add__(other)
def __sub__(self, other):
return MathComplex(self.real - other.real, self.imag - other.imag)
if isinstance(other, (int, float)):
return MathComplex(self.real - other.real, self.imag)
def __rsub__(self, other):
return self.__sub__(other)
def __mul__(self, other):
return MathComplex(self.real*other.real - self.imag*other.imag, self.real*other.imag + self.imag*other.real)
if isinstance(other, (int, float)):
return MathComplex(other*self.real, other*self.imag)
def __rmul__(self, other):
return self.__mul__(other)
def __truediv__(self, other):
real = (self.real*other.real + self.imag*other.imag) / (other.real**2 + other.imag**2)
imag = (self.imag*other.real - self.real*other.imag) / (other.real**2 + other.imag**2)
return MathComplex(real, imag)
if isinstance(other, (int, float)):
return MathComplex(self.real / other, self.imag / other)
def __rtruediv__(self, other):
return self.__truediv__(other)
def __neg__(self):
return MathComplex(self.imag)
if isinstance(self, (int, float)):
return 'Отсутствует мнимая часть'
def __eq__(self, other):
return self.real == other.real and self.imag == other.imag
def __round__(self, n):
return MathComplex(round(self.real, n), round(self.imag, n))
def conjugate(self):
self.imag = - self.imag
return MathComplex()
if isinstance(self, (int, float)):
return 'Отсутствует мнимая часть'
e = MathComplex()
a = MathComplex(2, 1)
b = MathComplex(4, 3)
d = 4
x = 4.67
assert str(a + e) == str(b + MathComplex(-2, -2)),
assert str(a - e) == str(a)
assert a - e == a
assert str(b * a) == str(MathComplex(5, 10))
assert str(b / a) == str(MathComplex(2.2, 0.4))
assert str(a + e) == str(e + a)
assert str(a - d) == str(MathComplex(-2, 1))
assert a - x == MathComplex(-2.67, 1)
assert str(b * d) == str(d * b)
assert round(abs(b / x), 4) == 1.0707