Learn Interfaces by Building an Equation Solver - Step 48

Tell us what’s happening:

for this i know i will have to defind an equation class somewhere but i don’t know how or where, at least thats wht i think i need to do

Your code so far

from abc import ABC, abstractmethod
import re


class Equation(ABC):
    degree: int
  
    def __init__(self, *args):
        if (self.degree + 1) != len(args):
            raise TypeError(
                f"'Equation' object takes {self.degree + 1} positional arguments but {len(args)} were given"
            )
        if any(not isinstance(arg, (int, float)) for arg in args):
            raise TypeError("Coefficients must be of type 'int' or 'float'")
        if args[0] == 0:
            raise ValueError("Highest degree coefficient must be different from zero")
        self.coefficients = {(len(args) - n - 1): arg for n, arg in enumerate(args)}

    def __init_subclass__(cls):
        if not hasattr(cls, "degree"):
            raise AttributeError(
                f"Cannot create '{cls.__name__}' class: missing required attribute 'degree'"
            )

    def __str__(self):
        terms = []
        for n, coefficient in self.coefficients.items():
            if not coefficient:
                continue
            if n == 0:
                terms.append(f'{coefficient:+}')
            elif n == 1:
                terms.append(f'{coefficient:+}x')
            else:
                terms.append(f"{coefficient:+}x**{n}")
        equation_string = ' '.join(terms) + ' = 0'
        return re.sub(r"(?<!\d)1(?=x)", "", equation_string.strip("+"))        

    @abstractmethod
    def solve(self):
        pass
        
    @abstractmethod
    def analyze(self):
        pass
        
class LinearEquation(Equation):
    degree = 1
    
    def solve(self):
        a, b = self.coefficients.values()
        x = -b / a
        return [x]

    def analyze(self):
        slope, intercept = self.coefficients.values()
        return {'slope': slope, 'intercept': intercept}

class QuadraticEquation(Equation):
    degree = 2
    

    def __init__(self, *args):
        super().__init__(*args)
        a, b, c = self.coefficients.values()
        self.delta = b**2 - 4 * a * c

    def solve(self):
        if self.delta < 0:
            return []
        a, b, _ = self.coefficients.values()
        x1 = (-b + (self.delta) ** 0.5) / (2 * a)
        x2 = (-b - (self.delta) ** 0.5) / (2 * a)
        if self.delta == 0:
            return [x1]

        return [x1, x2]

    def analyze(self):
        a, b, c = self.coefficients.values()
        x = -b / (2 * a)
        y = a * x**2 + b * x + c
        if a > 0:
            concavity = 'upwards'
            min_max = 'min'
        else:
            concavity = 'downwards'
            min_max = 'max'
        return {'x': x, 'y': y, 'min_max': min_max, 'concavity': concavity}

# User Editable Region

def solver(equation):
    if self.equation != Equation:
        raise TypeError('Argument must be an Equation object')

# User Editable Region

lin_eq = LinearEquation(2, 3)
quadr_eq = QuadraticEquation(1, 2, 1)
print(Equation.)


Your browser information:

User Agent is: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36

Challenge Information:

Learn Interfaces by Building an Equation Solver - Step 48

also tried testing the code through

print(quadr_eq.solver())

however i get an attribute error saying ‘QuadraticEquation’ object has no attribute ‘solver’

never mind my method wasn’t in the class smh

im still confused on the if equation != lin_eq: line tho its giving me a TypeError Argument must be an Equation object, i know its probably because of the lin_eq but dont know why

you are not checking if it’s not an instance, to do that you need to use something in particular

yes i know the self, and a instance is a variable in that class e.g. self.name = name inside a class, however, i dont see an self.equation = equation or anything of that sort anywhere

I am not sure I follow, equation is a parameter of the function solver, not an object property, you need to check if the function solver is being called with an argument of the right type

okay but when i go to test this code:

     if solver() != lin_eq:
            raise TypeError('Argument must be an Equation object')

it says NameError: name ‘solver’ is not defined

are you calling solver function inside the solver function? I am completely confused by what you are doing.
Also, where does lin_eq comes from?

okay so just to clarify this is my code now and im still working on it so expect changes:

from abc import ABC, abstractmethod
import re


class Equation(ABC):
    degree: int
  
    def __init__(self, *args):
        if (self.degree + 1) != len(args):
            raise TypeError(
                f"'Equation' object takes {self.degree + 1} positional arguments but {len(args)} were given"
            )
        if any(not isinstance(arg, (int, float)) for arg in args):
            raise TypeError("Coefficients must be of type 'int' or 'float'")
        if args[0] == 0:
            raise ValueError("Highest degree coefficient must be different from zero")
        self.coefficients = {(len(args) - n - 1): arg for n, arg in enumerate(args)}

    def __init_subclass__(cls):
        if not hasattr(cls, "degree"):
            raise AttributeError(
                f"Cannot create '{cls.__name__}' class: missing required attribute 'degree'"
            )

    def __str__(self):
        terms = []
        for n, coefficient in self.coefficients.items():
            if not coefficient:
                continue
            if n == 0:
                terms.append(f'{coefficient:+}')
            elif n == 1:
                terms.append(f'{coefficient:+}x')
            else:
                terms.append(f"{coefficient:+}x**{n}")
        equation_string = ' '.join(terms) + ' = 0'
        return re.sub(r"(?<!\d)1(?=x)", "", equation_string.strip("+"))        

    @abstractmethod
    def solve(self):
        pass
        
    @abstractmethod
    def analyze(self):
        pass
        
class LinearEquation(Equation):
    degree = 1
    
    def solve(self):
        a, b = self.coefficients.values()
        x = -b / a
        return [x]

    def analyze(self):
        slope, intercept = self.coefficients.values()
        return {'slope': slope, 'intercept': intercept}

class QuadraticEquation(Equation):
    degree = 2
    

    def __init__(self, *args):
        super().__init__(*args)
        a, b, c = self.coefficients.values()
        self.delta = b**2 - 4 * a * c

    def solve(self):
        if self.delta < 0:
            return []
        a, b, _ = self.coefficients.values()
        x1 = (-b + (self.delta) ** 0.5) / (2 * a)
        x2 = (-b - (self.delta) ** 0.5) / (2 * a)
        if self.delta == 0:
            return [x1]

        return [x1, x2]

    def analyze(self):
        a, b, c = self.coefficients.values()
        x = -b / (2 * a)
        y = a * x**2 + b * x + c
        if a > 0:
            concavity = 'upwards'
            min_max = 'min'
        else:
            concavity = 'downwards'
            min_max = 'max'
        return {'x': x, 'y': y, 'min_max': min_max, 'concavity': concavity}
    def solver(equation):
        if solver() != lin_eq:
            raise TypeError('Argument must be an Equation object')
lin_eq = LinearEquation(2, 3)
quadr_eq = QuadraticEquation(1, 2, 1)
print(quadr_eq.solver())


to answer your first question yes i am, i have now realised that it is wrong, but i don’t know how it’s wrong, also i don’t know why i put lin_eq there thinking about it now, however im pretty sure i done it because i realised you can’t just call on a class how it is

  1. solver is a global function, not a class method, restore that
  2. lin_eq can’t be used there, remove it from the if statement
  3. don’t call solver inside solver
  4. you must check if the function parameter equation is an instance of Equation, what do you must use here?

oh okay that makes more sense, i have restored it, okay i understand the 3rd one but where should i call it? well to check if a function parameter equation is an instance of an equation shouldn’t you use self on the equation there but how would you check if func parameter is an equation?

you have equation which is the function parameter, and Equation, which is the class. No self here because you are not inside a class.
You check if equation is an instance of Equation with the function you already used in the project that checks exactly that (if a thing is an instance of an other)

1 Like

okay, that helps alot i appreiciate it, im getting closer:

def solver(equation):
    if isinstance(equation,Equation):
        raise TypeError('Argument must be an Equation object')

however im still recieving error You should create an if statement to check if equation is not an instance of the Equation class within your solver function.

Read the error/hint carefully, word by word. It tells you exactly what you need to do.

1 Like