> For the complete documentation index, see [llms.txt](https://python-codelivly.gitbook.io/python-mastery-from-beginner-to-expert/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://python-codelivly.gitbook.io/python-mastery-from-beginner-to-expert/master-oop/inheritance.md).

# Inheritance&#x20;

nheritance is a fundamental concept in object-oriented programming (OOP) that allows a class to inherit the properties and methods of another class. In Python, inheritance enables us to create a new class (child class) that is a modified or specialized version of an existing class (parent class).

The child class can access all the attributes and methods of the parent class, and it can also override or extend those methods to add new functionality. This makes inheritance a powerful mechanism for code reuse and allows us to build complex applications with ease.

For example, imagine we have a class called `Animal` that defines basic attributes and methods for all animals, such as `name`, `age`, and `eat()`. We can create a child class called `Dog` that inherits from `Animal` and adds its own unique attributes and methods, such as `breed` and `bark()`.

Inheritance in Python is implemented using the keyword `class`, followed by the child class name and the name of the parent class in parentheses. Here's an example:

```ruby
class Animal:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def eat(self):
        print(f"{self.name} is eating.")

class Dog(Animal):
    def __init__(self, name, age, breed):
        super().__init__(name, age)
        self.breed = breed

    def bark(self):
        print("Woof!")
```

In this example, the `Dog` class inherits from the `Animal` class and adds a new attribute `breed` and a new method `bark()`. The `super()` function is used to call the constructor of the parent class and initialize its attributes.&#x20;

## Types of Inheritance&#x20;

In Python, there are several types of inheritance that you can use to create a child class. The most common types of inheritance are:

1. Single inheritance: In single inheritance, a child class inherits from a single parent class. This is the simplest and most common type of inheritance.
2. Multiple inheritance: In multiple inheritance, a child class inherits from two or more parent classes. This allows you to combine the features of multiple classes into a single class.
3. Multi-level inheritance: In multi-level inheritance, a child class inherits from a parent class, which in turn inherits from another parent class. This creates a hierarchical structure of classes.
4. Hierarchical inheritance: In hierarchical inheritance, multiple child classes inherit from a single parent class. This allows you to create a set of related classes with a common base class.
5. Hybrid inheritance: Hybrid inheritance is a combination of two or more types of inheritance. For example, you can use multiple inheritance along with multi-level inheritance to create a complex class hierarchy.

Each type of inheritance has its own advantages and disadvantages, and the choice of which type to use depends on the specific requirements of your application.

\
Inheritance Syntax&#x20;
------------------------

In Python, inheritance is implemented using the `class` keyword, followed by the name of the child class and the name of the parent class in parentheses. Here's the syntax for creating a child class that inherits from a parent class:

```ruby
class ParentClass:
    # Parent class attributes and methods

class ChildClass(ParentClass):
    # Child class attributes and methods
```

In this syntax, the `ParentClass` is the name of the parent class that the `ChildClass` is inheriting from. All the attributes and methods of the parent class are automatically inherited by the child class.

To access the parent class attributes and methods from the child class, you can use the `super()` function. The `super()` function returns a temporary object of the superclass, which allows you to call its methods.

Here's an example of inheritance in Python:

```ruby
class Animal:
    def __init__(self, name):
        self.name = name

    def eat(self):
        print(f"{self.name} is eating.")

class Dog(Animal):
    def __init__(self, name, breed):
        super().__init__(name)
        self.breed = breed

    def bark(self):
        print("Woof!")
```

In this example, the `Dog` class is inheriting from the `Animal` class. The `super()` function is used to call the constructor of the parent class and initialize its attributes.&#x20;

## Example : Python Inheritance  <a href="#example" id="example"></a>

Here's an example of how to use inheritance in Python to create a child class that inherits from a parent class:

```ruby
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def introduce(self):
        print(f"Hi, my name is {self.name} and I'm {self.age} years old.")

class Student(Person):
    def __init__(self, name, age, major):
        super().__init__(name, age)
        self.major = major

    def introduce(self):
        super().introduce()
        print(f"I'm studying {self.major} at the university.")
```

In this example, the `Person` class defines an `__init__()` method that initializes the `name` and `age` attributes and a `introduce()` method that introduces the person.

The `Student` class is a child class that inherits from the `Person` class. It adds a new attribute `major` and overrides the `introduce()` method to include information about the major.

The `super()` function is used to call the constructor of the parent class and initialize its attributes. It is also used to call the `introduce()` method of the parent class from within the `introduce()` method of the child class.

Here's an example of how to use these classes:

```python
person = Person("John", 25)
person.introduce()

student = Student("Jane", 20, "Computer Science")
student.introduce()
```

Output:

```python
Hi, my name is John and I'm 25 years old.
Hi, my name is Jane and I'm 20 years old.
I'm studying Computer Science at the university.
```

As you can see, the `Student` class inherits the `introduce()` method from the `Person` class and adds its own functionality to it. This is an example of how inheritance can be used to reuse code and build more complex classes from simpler ones.

## Accessing Parent Class from Child Class&#x20;

In Python, you can access the attributes and methods of the parent class from a child class using the `super()` function. The `super()` function returns a temporary object of the parent class, which allows you to call its methods and access its attributes.

Here's an example of how to access the parent class from a child class:

```python
class Parent:
    def __init__(self, name):
        self.name = name

    def greeting(self):
        print(f"Hello, my name is {self.name}.")

class Child(Parent):
    def __init__(self, name, age):
        super().__init__(name)
        self.age = age

    def greeting(self):
        super().greeting()
        print(f"I'm {self.age} years old.")
```

In this example, the `Child` class is inheriting from the `Parent` class. It overrides the `greeting()` method to include the age of the child.

The `super()` function is used to call the `greeting()` method of the parent class and include its output in the child class's greeting. This allows the child class to reuse the code of the parent class while adding its own functionality.

Here's an example of how to use these classes:

```python
parent = Parent("John")
parent.greeting()

child = Child("Jane", 10)
child.greeting()
```

Output:

```python
Hello, my name is John.
Hello, my name is Jane.
I'm 10 years old.
```

As you can see, the `Child` class is able to access the `name` attribute of the parent class and call its `greeting()` method using the `super()` function. This allows it to reuse the code of the parent class while adding its own functionality.<br>

## Overriding Methods in Child Class&#x20;

In Python, when a child class inherits from a parent class, it can override the parent class's methods with its own implementation. This is called method overriding.

To override a method in the child class, you simply define a method with the same name in the child class. When the method is called on an instance of the child class, the child class's implementation of the method will be used instead of the parent class's implementation.

Here's an example of method overriding in Python:

```python
class Parent:
    def say_hello(self):
        print("Hello from Parent class!")

class Child(Parent):
    def say_hello(self):
        print("Hello from Child class!")

parent = Parent()
parent.say_hello()  # Output: Hello from Parent class!

child = Child()
child.say_hello()  # Output: Hello from Child class!
```

In this example, the `Child` class is inheriting from the `Parent` class and overriding its `say_hello()` method with its own implementation. When the `say_hello()` method is called on an instance of the `Child` class, the child class's implementation is used instead of the parent class's implementation.

Note that when you override a method in the child class, the parent class's implementation is still available by using the `super()` function. Here's an example:

```python
class Parent:
    def say_hello(self):
        print("Hello from Parent class!")

class Child(Parent):
    def say_hello(self):
        super().say_hello()
        print("Hello from Child class!")

child = Child()
child.say_hello()  # Output: Hello from Parent class! Hello from Child class!
```

In this example, the `Child` class is using the `super()` function to call the `say_hello()` method of the parent class, and then adding its own implementation. This allows the child class to reuse the code of the parent class while adding its own functionality.&#x20;

## Using super() function in Child Class&#x20;

In Python, the `super()` function is used to call a method from the parent class in a child class. It is often used in conjunction with method overriding to reuse code from the parent class while adding additional functionality in the child class.

Here's an example of using the `super()` function in a child class:

```python
class Parent:
    def __init__(self, name):
        self.name = name

    def say_hello(self):
        print(f"Hello, my name is {self.name}.")

class Child(Parent):
    def __init__(self, name, age):
        super().__init__(name)
        self.age = age

    def say_hello(self):
        super().say_hello()
        print(f"I'm {self.age} years old.")

child = Child("Alice", 10)
child.say_hello()  # Output: Hello, my name is Alice. I'm 10 years old.
```

In this example, the `Child` class is inheriting from the `Parent` class and overriding its `say_hello()` method with its own implementation. The `super()` function is used to call the `say_hello()` method of the parent class and then add the child class's implementation. This allows the child class to reuse the code of the parent class while adding its own functionality.

Note that in the `__init__()` method of the `Child` class, the `super()` function is also used to call the `__init__()` method of the parent class. This ensures that the parent class's `__init__()` method is called before the child class's `__init__()` method, and that the `name` attribute is properly initialized.&#x20;

## Multiple Inheritance&#x20;

Multiple inheritance is a feature of object-oriented programming where a subclass can inherit from multiple parent classes. In Python, you can achieve multiple inheritance by specifying multiple parent classes in the class definition separated by commas.

Here's an example of multiple inheritance in Python:

```python
class Parent1:
    def method1(self):
        print("Method 1 from Parent 1")

class Parent2:
    def method2(self):
        print("Method 2 from Parent 2")

class Child(Parent1, Parent2):
    def method3(self):
        print("Method 3 from Child")

child = Child()
child.method1()  # Output: Method 1 from Parent 1
child.method2()  # Output: Method 2 from Parent 2
child.method3()  # Output: Method 3 from Child
```

In this example, the `Child` class is inheriting from both the `Parent1` and `Parent2` classes. It can access the methods of both parent classes using dot notation.

When a class inherits from multiple parent classes, it can override methods from both parent classes. If both parent classes have a method with the same name, the method in the first parent class listed in the inheritance statement will be called. If the child class needs to call a specific method from a specific parent class, it can do so using the `super()` function along with the parent class's name.

Here's an example of using the `super()` function to call a method from a specific parent class in a multiple inheritance scenario:

```python
class Parent1:
    def method(self):
        print("Method from Parent 1")

class Parent2:
    def method(self):
        print("Method from Parent 2")

class Child(Parent1, Parent2):
    def method(self):
        super(Parent1, self).method()

child = Child()
child.method()  # Output: Method from Parent 1
```

In this example, the `Child` class is inheriting from both the `Parent1` and `Parent2` classes, both of which have a method named `method()`. The `super()` function is used to call the `method()` of `Parent1`, so the output will be "Method from Parent 1".&#x20;

## Method Resolution Order (MRO)&#x20;

Method Resolution Order (MRO) is the order in which Python looks for methods in a class hierarchy. When a method is called on an instance of a class, Python first looks for the method in the instance's class. If the method is not found in the instance's class, Python looks for the method in the class's parent classes, following the MRO.

In Python, the MRO is determined using the C3 linearization algorithm, which is a special algorithm designed to create a linear order of inheritance hierarchy.

You can use the `mro()` method to get the MRO for a class. The `mro()` method returns a tuple that contains the class itself followed by the classes it inherits from, in the order that they will be searched for methods.

Here's an example of using the `mro()` method to get the MRO for a class:

```python
class Parent1:
    pass

class Parent2:
    pass

class Child(Parent1, Parent2):
    pass

print(Child.mro())  # Output: [<class '__main__.Child'>, <class '__main__.Parent1'>, <class '__main__.Parent2'>, <class 'object'>]
```

In this example, the `Child` class is inheriting from both the `Parent1` and `Parent2` classes. The `mro()` method is used to get the MRO for the `Child` class, which is a tuple that contains the `Child` class itself followed by the `Parent1` class, the `Parent2` class, and finally the built-in `object` class.

Understanding the MRO is important when dealing with multiple inheritance, as it determines the order in which Python will search for methods in the class hierarchy.&#x20;

## Diamond Problem in Multiple Inheritance&#x20;

The diamond problem is a common issue that arises in multiple inheritance when two parent classes of a child class inherit from the same base class. This results in the diamond shape of the class hierarchy, where the child class is at the bottom of the diamond and there are two paths to the base class.

Consider the following example:

```python
class A:
    def method(self):
        print("Method from A")

class B(A):
    pass

class C(A):
    def method(self):
        print("Method from C")

class D(B, C):
    pass

d = D()
d.method()  # Output: Method from C
```

In this example, the `D` class inherits from both `B` and `C`, which in turn both inherit from the `A` class. Both `B` and `C` have a method named `method()`, and when `D` calls the `method()` method, Python follows the MRO to look for the method in the class hierarchy. The MRO for `D` is `[D, B, C, A, object]`, which means that Python will first look for the `method()` method in the `B` class, then the `C` class, then the `A` class, and finally the `object` class.

In this case, Python finds the `method()` method in the `C` class first, and so it is called. This means that the `method()` method of `A` is never called, which can cause unexpected behavior if `C` is intended to override `A`.

To avoid the diamond problem, it's important to carefully design class hierarchies and avoid multiple inheritance where possible. When multiple inheritance is necessary, it's important to understand the MRO and the order in which methods will be searched for in the class hierarchy. You can also use the `super()` function to explicitly call methods in parent classes and avoid unintended method overrides.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://python-codelivly.gitbook.io/python-mastery-from-beginner-to-expert/master-oop/inheritance.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
