I am trying to write a class that simulates a complex number in Python. Yes, I know there already exists a built-in function called complex() which can be used to construct a complex number, and we can also use j to create them. However I wanted to write my own just for fun. Here is a small version of it:
class Complex:
def __init__(self, real: float = 0, img: float = 0):
self.real = real
self.img = img
self.num = (self.real, self.img)
def __repr__(self) -> str:
string = "{real}".format(real=self.real) if self.real != 0 else ""
# Want to have "a + bi", "a", "bi"
# Want to avoid "+ bi" or "a + "
if self.real != 0 and self.img < 0:
string += " - " # img will already have -
elif self.real != 0 and self.img > 0:
string += " + "
string += "{img}i".format(img=abs(self.img)) if self.img != 0 else ""
return string
def __add__(self, other: 'Complex') -> 'Complex':
return Complex(self.real + other.real, self.img + other.img)
def __sub__(self, other: 'Complex') -> 'Complex':
return Complex(self.real - other.real, self.img - other.img)
def __matmul__(self, other: 'Complex') -> 'Complex':
# (ac - bd)
real = self.real * other.real - self.img * other.img
# (ad + bc)
img = self.real * other.img + self.img * other.real
return Complex(real, img)
def __mul__(self, other):
return Complex(self.real * other, self.img * other)
def __rmul__(self, other):
return self.__mul__(other)
The issue is that I cannot find a way of defining the following:
- Complex * Complex (left multiplication for class instances)
- Complex * Complex (right multiplication for class instances, but useless as the above will suffice)
- float * Complex (right scalar multiplication, but can be with int as well)
- Complex * float (left scalar multiplication, but can be with int as well)
This is because when I multiply two class instances, it still calls __mul__ while it does not call __matmul__. I think __matmul__ should only work with @ operator. How can I make all of this work without having to use another operator (@) ? I would like to use the standard * operator.
__matmul__?__mul__is of typeComplexor of typeintorfloat__mul__is of typeComplexor of typeintorfloat" - just check already. It's the standard approach, and essentially mandatory.__add__or__mul__are supposed to take arbitrary types and returnNotImplementedif they don't recognize how to handle the argument.__repr__should be__str__; the string returned by__repr__should, to the extent possible, return a string that could be used to recreate the instance. In this case, something likereturn "Complex({}, {})".format(self.real, self.imag).