<jupyter_start><jupyter_text>Introduction **What?** Super()  What is super()? - While Python isn’t purely an object-oriented language, it’s flexible enough and powerful enough to allow you to build your applications using the object-oriented paradigm. - One of the ways in which Python achieves this is by supporting inheritance, which it does with `super()`.   Base class - We are going to create a base class.- Its methods will be inherited by a derived class.<jupyter_code>class Rectangle:
    def __init__(self, length, width):
        self.length = length
        self.width = width

    def area(self):
        return self.length * self.width

    def perimeter(self):
        return 2 * self.length + 2 * self.width<jupyter_output><empty_output><jupyter_text>Derived class withouth super()<jupyter_code>class Square:
    def __init__(self, length):
        self.length = length

    def area(self):
        return self.length * self.length

    def perimeter(self):
        return 4 * self.length<jupyter_output><empty_output><jupyter_text>Derived class with super() - We are jsut adding a `_m` to distinguish the classes from the previous case.- The `_m_v2` is to account for the Python 3, the `super(Square, self)` call is EQUIVALENT to the parameterless `super()` call. The first parameter refers to the subclass Square, while the second parameter refers to a Square object which, in this case, is self<jupyter_code># Here we declare that the Square class inherits from the Rectangle class
class Square_m(Rectangle):
    def __init__(self, length):
        super().__init__(length, length)
# Here we declare that the Square class inherits from the Rectangle class
class Square_m_v2(Rectangle):
    def __init__(self, length):
        super().__init__(length, length)<jupyter_output><empty_output><jupyter_text>Comparison<jupyter_code>rectangle = Rectangle(2,4)
print("Rectangle area", rectangle.area())<jupyter_output>Rectangle area 8<jupyter_text>- Nothing special in this call, but the code, however, doesn’t reflect that relationship and thus has code that is essentially **repeated**. - What if we can reuse the code written in the `Rectangle` class in the `Square` class.<jupyter_code>square = Square(4)
print("Square area (withouth super)", square.area())<jupyter_output>Square area (withouth super) 16<jupyter_text>- Here, you’ve used `super()` to call the `__init__()` of the Rectangle class, allowing you to use it in the Square class without repeating code. - The Square class inherited the `.area()` method from the Rectangle class.<jupyter_code>square_m = Square_m(4)
print("Square area (with super)", square_m.area())
square_m = Square_m_v2(4)
print("Square area (with super but how we used to do in python 2.x)", square_m.area())<jupyter_output>Square area (with super but how we used to do in python 2.x) 16<jupyter_text>Multiple Inheritance Overview  - In addition to single inheritance, Python supports multiple inheritance, in which a subclass can inherit from multiple superclasses that don’t necessarily inherit from each other (also known as sibling classes).  ![image.png](attachment:image.png)<jupyter_code>class Triangle_SC1:
    """
    Superclass No1
    """
    def __init__(self, base, height):
        self.base = base
        self.height = height

    def area(self):
        print("Using area from square_C1")
        return 0.5 * self.base * self.height
class Square_SC2:
    """
    Superclass No2
    """
    def __init__(self, length):
        self.length = length

    def area(self):
        print("Using area from square_C2")        
        return self.length * self.length

    def perimeter(self):
        return 4 * self.length<jupyter_output><empty_output><jupyter_text>- The problem, though, is that both superclasses (Triangle and Square) define a .area(). - The **method resolution order (or MRO)** tells Python how to search for inherited methods. - This comes in handy when you’re using super() because the MRO tells you exactly where Python will look for a method you’re calling with super() and in what order.<jupyter_code>class RightPyramid(Square_SC2, Triangle_SC1):
    """
    The signature of the class is important.
    Writing (Square, Triangle) is not the same as (Triangle, Square)
    """
    def __init__(self, base, slant_height):
        self.base = base
        self.slant_height = slant_height
        super().__init__(self.base)

    def area(self):
        base_area = super().area()
        perimeter = super().perimeter()
        return 0.5 * perimeter * self.slant_height + base_area
RightPyramid.__mro__
pyramid = RightPyramid(2, 4)
pyramid.area()<jupyter_output>Using area from square_C2
{'fraction_non_alphanumeric': 0.0920968087384879, 'fraction_numerical': 0.0074962518740629685, 'mean_word_length': 4.0269106566200215, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '8', 'dir': 'jupyter-structured-clean-dedup', 'id': '468254', 'license': 'OLDAP-2.3', 'n_tokens_mistral': 1391, 'n_tokens_neox': 1335, 'n_words': 508, 'path': 'GitHub_MD_rendering/Super().ipynb', 'repo_name': 'kyaiooiayk/Python-Programming', 'size': '4669'}