Python Inheritance

Learn about inheritance in Python - how to create new classes based on existing classes.

Python Inheritance

Inheritance allows us to define a class that inherits all the methods and properties from another class.

Parent class is the class being inherited from, also called base class.

Child class is the class that inherits from another class, also called derived class.

Create a Parent Class

Any class can be a parent class, so the syntax is the same as creating any other class:

Example - Create a class named Person, with firstname and lastname properties, and a printname method:

class Person:
    def __init__(self, fname, lname):
        self.firstname = fname
        self.lastname = lname

    def printname(self):
        print(self.firstname, self.lastname)

# Use the Person class to create an object, and then execute the printname method:
x = Person("John", "Doe")
x.printname()

Create a Child Class

To create a class that inherits the functionality from another class, send the parent class as a parameter when creating the child class:

Example - Create a class named Student, which will inherit the properties and methods from the Person class:

class Person:
    def __init__(self, fname, lname):
        self.firstname = fname
        self.lastname = lname

    def printname(self):
        print(self.firstname, self.lastname)

class Student(Person):
    pass

x = Student("Mike", "Olsen")
x.printname()

Note: Use the pass keyword when you do not want to add any other properties or methods to the class.

Now the Student class has the same properties and methods as the Person class.

Add the __init__() Function

So far we have created a child class that inherits the properties and methods from its parent.

We want to add the __init__() function to the child class (instead of the pass keyword).

Note: The __init__() function is called automatically every time the class is being used to create a new object.

Example - Add the __init__() function to the Student class:

class Person:
    def __init__(self, fname, lname):
        self.firstname = fname
        self.lastname = lname

    def printname(self):
        print(self.firstname, self.lastname)

class Student(Person):
    def __init__(self, fname, lname):
        # add properties etc.

x = Student("Mike", "Olsen")

When you add the __init__() function, the child class will no longer inherit the parent's __init__() function.

Note: The child's __init__() function overrides the inheritance of the parent's __init__() function.

To keep the inheritance of the parent's __init__() function, add a call to the parent's __init__() function:

Example

class Person:
    def __init__(self, fname, lname):
        self.firstname = fname
        self.lastname = lname

    def printname(self):
        print(self.firstname, self.lastname)

class Student(Person):
    def __init__(self, fname, lname):
        Person.__init__(self, fname, lname)

x = Student("Mike", "Olsen")
x.printname()

Now we have successfully added the __init__() function, and kept the inheritance of the parent class, and we are ready to add functionality in the __init__() function.

Use the super() Function

Python also has a super() function that will make the child class inherit all the methods and properties from its parent:

Example

class Person:
    def __init__(self, fname, lname):
        self.firstname = fname
        self.lastname = lname

    def printname(self):
        print(self.firstname, self.lastname)

class Student(Person):
    def __init__(self, fname, lname):
        super().__init__(fname, lname)

x = Student("Mike", "Olsen")
x.printname()

By using the super() function, you do not have to use the name of the parent element, it will automatically inherit the methods and properties from its parent.

Add Properties

Example - Add a property called graduationyear to the Student class:

class Person:
    def __init__(self, fname, lname):
        self.firstname = fname
        self.lastname = lname

    def printname(self):
        print(self.firstname, self.lastname)

class Student(Person):
    def __init__(self, fname, lname):
        super().__init__(fname, lname)
        self.graduationyear = 2019

x = Student("Mike", "Olsen")
print(x.graduationyear)

In the example below, the year 2019 should be a variable, and passed into the Student class when creating student objects. To do so, add another parameter in the __init__() function:

Example - Add a year parameter, and pass the correct year when creating objects:

class Person:
    def __init__(self, fname, lname):
        self.firstname = fname
        self.lastname = lname

    def printname(self):
        print(self.firstname, self.lastname)

class Student(Person):
    def __init__(self, fname, lname, year):
        super().__init__(fname, lname)
        self.graduationyear = year

x = Student("Mike", "Olsen", 2019)
print(x.graduationyear)

Add Methods

Example - Add a method called welcome to the Student class:

class Person:
    def __init__(self, fname, lname):
        self.firstname = fname
        self.lastname = lname

    def printname(self):
        print(self.firstname, self.lastname)

class Student(Person):
    def __init__(self, fname, lname, year):
        super().__init__(fname, lname)
        self.graduationyear = year

    def welcome(self):
        print("Welcome", self.firstname, self.lastname, "to the class of", self.graduationyear)

x = Student("Mike", "Olsen", 2019)
x.welcome()

If you add a method in the child class with the same name as a function in the parent class, the inheritance of the parent method will be overridden.

Method Overriding

Child classes can override methods from their parent classes:

Example - Method overriding:

class Animal:
    def __init__(self, name):
        self.name = name
    
    def speak(self):
        return f"{self.name} makes a sound"
    
    def move(self):
        return f"{self.name} moves"

class Dog(Animal):
    def __init__(self, name, breed):
        super().__init__(name)
        self.breed = breed
    
    def speak(self):  # Override parent method
        return f"{self.name} barks"
    
    def fetch(self):  # New method specific to Dog
        return f"{self.name} fetches the ball"

class Cat(Animal):
    def __init__(self, name, color):
        super().__init__(name)
        self.color = color
    
    def speak(self):  # Override parent method
        return f"{self.name} meows"
    
    def climb(self):  # New method specific to Cat
        return f"{self.name} climbs the tree"

# Usage
dog = Dog("Buddy", "Golden Retriever")
cat = Cat("Whiskers", "Orange")

print(dog.speak())    # Buddy barks
print(dog.move())     # Buddy moves (inherited)
print(dog.fetch())    # Buddy fetches the ball

print(cat.speak())    # Whiskers meows
print(cat.climb())    # Whiskers climbs the tree

Multiple Inheritance

Python supports multiple inheritance, where a class can inherit from multiple parent classes:

Example - Multiple inheritance:

class Mammal:
    def __init__(self, name):
        self.name = name
        self.warm_blooded = True
    
    def breathe(self):
        return f"{self.name} breathes air"

class Carnivore:
    def __init__(self):
        self.diet = "meat"
    
    def hunt(self):
        return f"Hunting for prey"

class Lion(Mammal, Carnivore):
    def __init__(self, name, pride_size):
        Mammal.__init__(self, name)
        Carnivore.__init__(self)
        self.pride_size = pride_size
    
    def roar(self):
        return f"{self.name} roars loudly"
    
    def hunt(self):  # Override Carnivore's hunt method
        return f"{self.name} hunts with the pride of {self.pride_size}"

# Usage
lion = Lion("Simba", 8)
print(lion.breathe())       # Simba breathes air
print(lion.hunt())          # Simba hunts with the pride of 8
print(lion.roar())          # Simba roars loudly
print(f"Diet: {lion.diet}") # Diet: meat

Method Resolution Order (MRO)

When using multiple inheritance, Python uses Method Resolution Order to determine which method to call:

Example - Understanding MRO:

class A:
    def method(self):
        return "Method from A"

class B(A):
    def method(self):
        return "Method from B"

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

class D(B, C):
    pass

# Check the Method Resolution Order
print(D.__mro__)
# (, , , , )

d = D()
print(d.method())  # Method from B (B comes before C in MRO)

# You can also check MRO with mro() method
print(D.mro())

Abstract Base Classes

Use abstract base classes to define interfaces that subclasses must implement:

Example - Abstract base class:

from abc import ABC, abstractmethod

class Vehicle(ABC):
    def __init__(self, make, model):
        self.make = make
        self.model = model
    
    @abstractmethod
    def start_engine(self):
        pass
    
    @abstractmethod
    def stop_engine(self):
        pass
    
    def get_info(self):
        return f"{self.make} {self.model}"

class Car(Vehicle):
    def __init__(self, make, model, doors):
        super().__init__(make, model)
        self.doors = doors
    
    def start_engine(self):
        return f"{self.make} {self.model} engine started with key"
    
    def stop_engine(self):
        return f"{self.make} {self.model} engine stopped"

class Motorcycle(Vehicle):
    def __init__(self, make, model, engine_size):
        super().__init__(make, model)
        self.engine_size = engine_size
    
    def start_engine(self):
        return f"{self.make} {self.model} engine started with button"
    
    def stop_engine(self):
        return f"{self.make} {self.model} engine stopped"

# Usage
car = Car("Toyota", "Camry", 4)
bike = Motorcycle("Honda", "CBR", 600)

print(car.get_info())        # Toyota Camry
print(car.start_engine())    # Toyota Camry engine started with key
print(bike.start_engine())   # Honda CBR engine started with button

# This would raise an error:
# vehicle = Vehicle("Generic", "Vehicle")  # TypeError: Can't instantiate abstract class

Practical Example: Employee Management System

Complete inheritance example:

from abc import ABC, abstractmethod
from datetime import datetime

class Employee(ABC):
    def __init__(self, employee_id, name, email):
        self.employee_id = employee_id
        self.name = name
        self.email = email
        self.hire_date = datetime.now()
    
    @abstractmethod
    def calculate_salary(self):
        pass
    
    def get_info(self):
        return f"ID: {self.employee_id}, Name: {self.name}, Email: {self.email}"
    
    def years_of_service(self):
        return (datetime.now() - self.hire_date).days // 365

class FullTimeEmployee(Employee):
    def __init__(self, employee_id, name, email, annual_salary):
        super().__init__(employee_id, name, email)
        self.annual_salary = annual_salary
    
    def calculate_salary(self):
        return self.annual_salary / 12  # Monthly salary

class PartTimeEmployee(Employee):
    def __init__(self, employee_id, name, email, hourly_rate, hours_per_week):
        super().__init__(employee_id, name, email)
        self.hourly_rate = hourly_rate
        self.hours_per_week = hours_per_week
    
    def calculate_salary(self):
        return self.hourly_rate * self.hours_per_week * 4  # Monthly salary

class Manager(FullTimeEmployee):
    def __init__(self, employee_id, name, email, annual_salary, team_size):
        super().__init__(employee_id, name, email, annual_salary)
        self.team_size = team_size
        self.team_members = []
    
    def add_team_member(self, employee):
        self.team_members.append(employee)
    
    def calculate_salary(self):
        base_salary = super().calculate_salary()
        bonus = self.team_size * 500  # $500 bonus per team member
        return base_salary + bonus
    
    def get_team_info(self):
        team_info = f"Manager: {self.name}\nTeam Size: {self.team_size}\nTeam Members:\n"
        for member in self.team_members:
            team_info += f"  - {member.name}\n"
        return team_info

class Contractor(Employee):
    def __init__(self, employee_id, name, email, project_rate, contract_duration):
        super().__init__(employee_id, name, email)
        self.project_rate = project_rate
        self.contract_duration = contract_duration  # in months
    
    def calculate_salary(self):
        return self.project_rate / self.contract_duration

# Usage
# Create employees
ft_employee = FullTimeEmployee("FT001", "Alice Johnson", "alice@company.com", 60000)
pt_employee = PartTimeEmployee("PT001", "Bob Smith", "bob@company.com", 25, 20)
manager = Manager("MG001", "Carol Davis", "carol@company.com", 80000, 3)
contractor = Contractor("CT001", "David Wilson", "david@company.com", 15000, 6)

# Add team members to manager
manager.add_team_member(ft_employee)
manager.add_team_member(pt_employee)

# Display information
employees = [ft_employee, pt_employee, manager, contractor]

for emp in employees:
    print(f"\n{emp.get_info()}")
    print(f"Monthly Salary: ${emp.calculate_salary():.2f}")
    print(f"Years of Service: {emp.years_of_service()}")
    
    if isinstance(emp, Manager):
        print(emp.get_team_info())

super() and Method Overriding

A subclass can override a parent method and still call the parent version with super().

class Animal:
    def __init__(self, name):
        self.name = name
    def speak(self):
        return "some sound"

class Dog(Animal):
    def __init__(self, name, breed):
        super().__init__(name)     # run the parent constructor
        self.breed = breed
    def speak(self):               # override
        return "Woof!"

d = Dog("Rex", "Lab")
print(d.name, d.breed, d.speak())   # Rex Lab Woof!
print(isinstance(d, Animal))        # True

Types of Inheritance

TypeShape
SingleB inherits A
MultilevelC inherits B inherits A
MultipleC inherits A and B
HierarchicalB and C both inherit A

With multiple inheritance, Python resolves method lookup using the MRO (Method Resolution Order). Inspect it with ClassName.__mro__.

Try It Yourself

Exercise 1: Make a Cat subclass of Animal whose speak() returns "Meow".

Show solution
class Cat(Animal):
    def speak(self):
        return "Meow"

print(Cat("Tom").speak())   # Meow

Exercise 2: In a subclass constructor, call the parent's __init__ with super().

Show solution
class Bird(Animal):
    def __init__(self, name, can_fly):
        super().__init__(name)
        self.can_fly = can_fly

b = Bird("Sky", True)
print(b.name, b.can_fly)   # Sky True

Key Takeaways

  • A subclass reuses and extends a parent class.
  • Override methods to specialize; call super() to reuse parent logic.
  • isinstance and issubclass test relationships.

📘 Real-World Deep Dive

Inheritance models an "is-a" relationship. It's easy to over-use — prefer composition unless the subclass really does behave like the parent and adds new behaviour.

Real-Life Scenario

A small reporting hierarchy — <code>Report</code> base, two specialised subclasses with overrides and extra state.

Real-Life Example

from dataclasses import dataclass, field

@dataclass
class Report:
    title: str
    rows: list[list[str]] = field(default_factory=list)

    def render(self) -> str:
        return f"# {self.title}\n\n" + "\n".join(", ".join(r) for r in self.rows) + "\n"

@dataclass
class MarkdownReport(Report):
    def render(self) -> str:
        header = "| " + " | ".join(self.rows[0]) + " |\n"
        sep = "|" + "|".join("---" for _ in self.rows[0]) + "|\n"
        body = "".join("| " + " | ".join(r) + " |\n" for r in self.rows[1:])
        return f"# {self.title}\n\n{header}{sep}{body}"

@dataclass
class TsvReport(Report):
    delim: str = "\t"
    def render(self) -> str:
        return (
            f"# {self.title}\n"
            + "\n".join(self.delim.join(r) for r in self.rows) + "\n"
        )

base = Report("Users", [["name", "age"], ["Ada", "29"], ["Bo", "41"]])
md   = MarkdownReport("Users", base.rows)
tsv  = TsvReport("Users", base.rows, delim="\t")
print(md.render())
print(tsv.render())

Expected Output

# Users

| name | age |
|---|---|
| Ada | 29 |
| Bo | 41 |

# Users
name	age
Ada	29
Bo	41

Common mistakes

  • Don't use inheritance to share code; that's composition's job. Inherit only when you really mean "is-a".
  • Calling super().method(...) correctly is easy to forget; use super().__init__ raises a TypError hint.
  • Multiple inheritance with MRO surprises — stick to mixins (class Foo(Bar, JsonMixin)) and single inheritance.

🚀 Performance & Best Practices

  • Method lookup in Python is a chain; deep hierarchies are slow per call but rarely matter.
  • Use type(self).__mro__ to introspect the lookup order at runtime if needed.
  • Abstract base classes (abc.ABC) are great for documenting interfaces, not for shared state.

🧪 Try It Yourself

  1. Add a JsonReport(Report) subclass that uses json.dumps(rows).
  2. Refactor MarkdownReport/TsvReport to a single class with a format: str field.
  3. Write a base CachedReport mixin and apply to MarkdownReport.

FAQ: Python Inheritance

Common questions about this page.

What is Python Inheritance?

Python Inheritance is a Python Tutorial lesson that explains python inheritance in Python. Learn about inheritance in Python - how to create new classes based on existing classes. Copy the samples and run them in the Python editor. It is written for beginners who want a clear definition and working examples.

Should I run python inheritance examples locally for better learning?

Yes. Use the browser editor on StudyGrid for a quick check, then Download the example and run it on your computer. Local runs show real errors and the real toolchain, which is one of the fastest ways to learn python inheritance in this Python Tutorial Python lesson (Python Inheritance).

How do I use python inheritance in Python?

To use python inheritance in Python, follow the examples on this StudyGrid page. Copy a snippet, run it in the browser, then Download and run it locally for better learning. Change the values and compare the output.

What is the syntax of python inheritance?

This Python Inheritance tutorial shows python inheritance syntax with short Python examples. Use the code blocks in this lesson for the exact statements, then try them in your editor.

Python Inheritance example for beginners

Yes. This page includes a beginner python inheritance example you can copy and run. It is designed for searches such as "python inheritance for beginners", "python inheritance example", and "how to use python inheritance".

What are common mistakes with python inheritance?

Common python inheritance mistakes include wrong syntax, mixing types, and skipping practice. Work through this Python Tutorial chapter in order, run every example, and check the output before moving on.

Why should I learn python inheritance?

Python Inheritance is used in real Python work. Learning python inheritance helps you write clearer programs and continue the Python Tutorial tutorial on StudyGrid.

Is Python Inheritance free to learn online?

Yes. You can learn python inheritance free on StudyGrid (studygrid.in). This chapter is part of the Python Tutorial path and includes examples, syntax, and next-step links.