Python Quadratic object (with __dunder__ methods)

I tried to make a Python class to for a Quadratic polynomial
with some “dunder” methods to overload the operators + and -, and to use () and [], and to try to make it iterable.
There’s methods for the Quadratic Formula (real number version only) and related stuff.
I also messed with the dict keyword close to the end of the code.

from math import sqrt #import cmath # complex numbers library class Quadratic(): def __init__(self, a = 1.0, b = 0.0, c = 0.0): if isinstance(a, list): length = len(a) if (length > 0): self.c = a[0] else: self.c = 0 if (length > 1): self.b = a[1] else: self.b = 0 if (length > 2): self.a = a[2] else: self.a = 0 elif isinstance(a, dict): try: self.a = a['a'] except: self.a = 1 try: self.b = a['b'] except: self.b = 0 try: self.c = a['c'] except: self.c = 0 else: # a is not a list nor a dict self.a = a self.b = b self.c = c if (self.a == 0): print("not a quadratic") @staticmethod def create(lst): return Quadratic(*lst) def __call__(self, x): return (self.a * (x ** 2)) + (self.b * x) + self.c def __repr__(self): return str(self.a) + "x^2 + " + str(self.b) + "x + " + str(self.c) def roots(self): a = self.a b = self.b c = self.c d = (b ** 2) - (4 * a * c) # discriminant if (a != 0): if (d > 0): return [ (-b - sqrt(d)) / (2 * a) , (-b + sqrt(d)) / (2 * a) ] elif (d == 0): return [ -b / (2 * a) ] else: #(d < 0): return [] #return [ (-b - cmath.sqrt(d)) / (2 * a) , (-b + cmath.sqrt(d)) / (2 * a) ] else: #(a == 0): return [ -c / b ] """ def __list__(self): return [self.c, self.b, self.a] """ def __add__(self, other): if isinstance(other, Quadratic): a = self.a + other.a b = self.b + other.b c = self.c + other.c return Quadratic(a, b, c) else: c = self.c + other return Quadratic(self.a, self.b, c) def __sub__(self, other): if isinstance(other, Quadratic): a = self.a - other.a b = self.b - other.b c = self.c - other.c return Quadratic(a, b, c) else: c = self.c - other return Quadratic(self.a, self.b, c) def __neg__(self): return Quadratic(-self.a, -self.b, -self.c) def __rsub__(self, other): c = other - self.c return Quadratic(-self.a, -self.b, c) def __mul__(self, other): a = self.a * other b = self.b * other c = self.c * other return Quadratic(a, b, c) def __div__(self, other): a = self.a / other b = self.b / other c = self.c / other return Quadratic(a, b, c) def __rmul__(self, other): return self.__mul__(other) def __eq__(self, other): try: return ( \ (self.a == other.a) and \ (self.b == other.b) and \ (self.c == other.c) ) except: return ( \ (self.a == 0) and \ (self.b == 0) and \ (self.c == other) ) def __len__(self): return 3 def __getitem__(self, index): if (type(index) == int): if (index < 0): index = index + 2 if (index == 0): return self.c elif (index == 1): return self.b elif (index == 2): return self.a elif (index == 'a'): return self.a elif (index == 'b'): return self.b elif (index == 'c'): return self.c raise IndexError def __setitem__(self, index, value): if (type(index) == int): if (index < 0): index = index + 2 if (index == 0): self.c = value elif (index == 1): self.b = value elif (index == 2): self.a = value elif (index == 'a'): self.a = value elif (index == 'b'): self.b = value elif (index == 'c'): self.c = value #raise IndexError def __iter__(self): # iterate inside for-in loop return iter([self.c, self.b, self.a]) # does not support assignment inside for-in loop def vertex(self): x = - self.b / (2 * self.a) return (x, self.__call__(x)) def focus(self): x = - self.b / (2 * self.a) y = self.__call__(x) + (a / 4) return (x, y) @staticmethod def from_roots(r1, r2 = None): if (r2 is None): r2 = r1 b = r1 + r2 c = r1 * r2 return Quadratic(1, b, c) # end of Quadratic class # f = Quadratic(1, -2, -3) print("f(x) =", f) a = 5 print(f'f({a}) =' , f(a)) #g = f + 4 #print('f + 4 = ', g) print("roots", end = " ") print(f.roots()) print("vertex", f.vertex()) print("focus", f.focus()) g = Quadratic([5, 6, 1]) print(g) h = Quadratic.create([-2, 5, 1]) print(h) y = g + h print(y) #z = Quadratic({'a': 2, 'b': -6, 'c': 1}) #y = Quadratic.from_roots(1) print('y =', y) for co in y: print(co) Dictionary = dict def dict(obj): try: return Dictionary(obj) except: if isinstance(obj, list): length = len(obj) keys = list(range(length)) return Dictionary(zip(keys, obj)) return obj.__dict__ print(dict( [('e', 1), ('f', 2)] )) print(dict( [5, 6] )) print(dict(f)) print(list(f)) def maximum(stuff): if isinstance(stuff, Quadratic): if (stuff.a < 0): return stuff.vertex()[1] else: return max(stuff) def minimum(stuff): if isinstance(stuff, Quadratic): if (stuff.a > 0): return stuff.vertex()[1] else: return min(stuff) print("h =", h) print("max: ", maximum(h)) print("f =", f) print("min: ", minimum(f))

Please let me know if you find any bugs, or any way to improve the code.