Back to Freecodecamp

Step 49

curriculum/challenges/english/blocks/learn-interfaces-by-building-an-equation-solver/66562f71937f877c66123bbe.md

latest4.6 KB
Original Source

--description--

The first thing to display at the top of the output will be the equation type. Add a class attribute named type to the Equation class and annotate it with str.

Then, add another if statement to the __init_subclass__ method to check if the classes inheriting from Equation have the type attribute. Use the same format of the existing if statement with the appropriate modifications.

Finally, add the new class attribute to the LinearEquation class and to the QuadraticEquation class. Assign it the string 'Linear Equation' and the string 'Quadratic Equation', respectively.

--hints--

You should define a class variable named type within the Equation class and annotate it with str.

js
({ test: () => assert(runPython(`_Node(_code).find_class("Equation").has_stmt("type: str")`)) })

You should create an if statement that checks if cls does not have the attribute type inside the __init_subclass__ method and raise an AttributeError using the provided string.

js
({ test: () => assert(runPython(`
if_str = """
if not hasattr(cls, 'type'):
  raise AttributeError(
    f\\"Cannot create '{cls.__name__}' class: missing required attribute 'type'\\"
  )
"""
_Node(_code).find_class("Equation").find_function("__init_subclass__").has_stmt(if_str)
`)) })

The type attribute of the LinearEquation class shouls have the value 'Linear Equation'.

js
({ test: () => assert(runPython(`_Node(_code).find_class("LinearEquation").has_stmt("type = 'Linear Equation'")`)) })

The type attribute of the QuadraticEquation class should have the value 'Quadratic Equation'.

js
({ test: () => assert(runPython(`_Node(_code).find_class("QuadraticEquation").has_stmt("type = 'Quadratic Equation'")`)) })

--seed--

--seed-contents--

py
from abc import ABC, abstractmethod
import re

--fcc-editable-region--
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
--fcc-editable-region--
    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 not isinstance(equation, Equation):
        raise TypeError("Argument must be an Equation object")


lin_eq = LinearEquation(2, 3)
quadr_eq = QuadraticEquation(1, 2, 1)