Understanding inheritance and polymorphism in Python: creation and use of subclasses to expand functionality.

онлайн тренажер по питону
Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

A self-study guide for Python 3 compiled from the materials on this site. Primarily intended for those who want to learn the Python programming language from scratch.

What is inheritance in Python

Inheritance is an OOP mechanism that allows you to create a new class based on an existing one. The child class automatically receives all the attributes and methods of the parent class, and can also add its own or override inherited ones.

Inheritance syntax

class BaseClass:
    def __init__(self, base_attr):
        self.base_attr = base_attr

    def base_method(self):
        print("Method from BaseClass")

class DerivedClass(BaseClass):
    def __init__(self, base_attr, derived_attr):
        super().__init__(base_attr)  # Calling the parent constructor
        self.derived_attr = derived_attr

    def derived_method(self):
        print("Method from DerivedClass")

# Creating a child class object
derived = DerivedClass("Base Attribute", "Derived Attribute")
derived.base_method()    # Output: Method from BaseClass
derived.derived_method() # Output: Method from DerivedClass

super() function in Python

The super() function provides access to the methods of the parent class, which is especially important when redefining methods.:

class Employee:
    def __init__(self, name, salary):
        self.name = name
        self.salary = salary
    
    def get_info(self):
        return f"Employee: {self.name}, Salary: {self.salary}"

class Manager(Employee):
    def __init__(self, name, salary, department):
        super().__init__(name, salary) # Calling the parent constructor
        self.department = department
    
    def get_info(self):
        base_info = super().get_info() # Getting information from the parent
        return f"{base_info}, Department: {self.department}"

manager = Manager("John", 50000, "IT")
print(manager.get_info())  # Employee: John, Salary: 50000, Department: IT

Polymorphism in Python

Polymorphism is the ability of objects of different classes to respond to the same method calls in different ways. In Python, polymorphism is implemented through redefinition of methods.

Basic example of polymorphism

class Animal:
    def make_sound(self):
        pass

class Dog(Animal):
    def make_sound(self):
        return "Woof!"

class Cat(Animal):
    def make_sound(self):
        return "Meow!"

class Bird(Animal):
    def make_sound(self):
        return "Tweet!"

# Polymorphic use
of animals = [Dog(), Cat(), Bird()]

for animal in animals:
    print(animal.make_sound())
# Conclusion:
# Woof!
# Meow!
# Tweet!

A practical example: a payment system

class PaymentMethod:
    def process_payment(self, amount):
        raise NotImplementedError("Subclass must implement")

class CreditCard(PaymentMethod):
    def __init__(self, card_number):
        self.card_number = card_number
    
    def process_payment(self, amount):
        return f"Processing ${amount} via Credit Card ending in {self.card_number[-4:]}"

class PayPal(PaymentMethod):
    def __init__(self, email):
        self.email = email
    
    def process_payment(self, amount):
        return f"Processing ${amount} via PayPal account {self.email}"

class BankTransfer(PaymentMethod):
    def __init__(self, account_number):
        self.account_number = account_number
    
    def process_payment(self, amount):
        return f"Processing ${amount} via Bank Transfer to {self.account_number}"

# Function for processing a payment in any way
def make_payment(payment_method, amount):
    return payment_method.process_payment(amount)

# Using
credit_card = CreditCard("1234567890123456")
paypal = PayPal("user@example.com ")
bank_transfer = BankTransfer("ACC123456789")

print(make_payment(credit_card, 100))
print(make_payment(paypal, 50))
print(make_payment(bank_transfer, 200))

Advanced examples of inheritance and polymorphism

An example with geometric shapes

import math

class Shape:
    def __init__(self, name):
        self.name = name
    
    def area(self):
        raise NotImplementedError("Subclass must implement area method")
    
    def perimeter(self):
        raise NotImplementedError("Subclass must implement perimeter method")
    
    def __str__(self):
        return f"{self.name} - Area: {self.area():.2f}, Perimeter: {self.perimeter():.2f}"

class Circle(Shape):
    def __init__(self, radius):
        super().__init__("Circle")
        self.radius = radius

    def area(self):
        return math.pi * self.radius ** 2

    def perimeter(self):
        return 2 * math.pi * self.radius

class Rectangle(Shape):
    def __init__(self, width, height):
        super().__init__("Rectangle")
        self.width = width
        self.height = height

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

    def perimeter(self):
        return 2 * (self.width + self.height)

class Triangle(Shape):
    def __init__(self, a, b, c):
        super().__init__("Triangle")
        self.a = a
        self.b = b
        self.c = c

    def area(self):
        s = self.perimeter() / 2
        return math.sqrt(s * (s - self.a) * (s - self.b) * (s - self.c))

    def perimeter(self):
        return self.a + self.b + self.c

# Creating
a shapes collection = [
    Circle(5),
    Rectangle(4, 6),
    Triangle(3, 4, 5)
]

# Polymorphic usage
for shape in shapes:
    print(shape)

Multiple inheritance

Python supports multiple inheritance - the ability to inherit from multiple classes:

class Flyable:
    def fly(self):
        return "Flying through the air"

class Swimmable:
    def swim(self):
        return "Swimming in water"

class Duck(Animal, Flyable, Swimmable):
    def make_sound(self):
        return "Quack!"

duck = Duck()
print(duck.make_sound())  # Quack!
print(duck.fly())         # Flying through the air
print(duck.swim())        # Swimming in water

Abstract classes and methods

Abstract classes are used to create a stricter class hierarchy.:

from abc import ABC, abstractmethod

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

class Car(Vehicle):
    def start_engine(self):
        return "Car engine started"
    
    def stop_engine(self):
        return "Car engine stopped"

class Motorcycle(Vehicle):
    def start_engine(self):
        return "Motorcycle engine started"
    
    def stop_engine(self):
        return "Motorcycle engine stopped"

# Creating objects
car = Car("Toyota", "Camry")
motorcycle = Motorcycle("Honda", "CBR")

print(car.get_info())        # Toyota Camry
print(car.start_engine())    # Car engine started
print(motorcycle.start_engine())  # Motorcycle engine started

Advantages of inheritance and polymorphism

Main advantages:

Code reuse: Avoiding code duplication by inheriting common functionality.

Extensibility: Easily adding new classes without changing existing code.

Polymorphism: A single interface for working with objects of different types.

Encapsulation: Hiding implementation details and providing a simple interface.

Modularity: Separation of code into logical components.

The principle of substitution of Liskov

An important principle of OOP: superclass objects should be replaced by subclass objects without disrupting the program:

def process_shapes(shapes_list):
    total_area = 0
    for shape in shapes_list:
total_area += shape.area() # Works for any Shape subclass
    return total_area

# The function works with any inheritors of Shape
mixed_shapes = [Circle(3), Rectangle(2, 4), Triangle(3, 4, 5)]
total = process_shapes(mixed_shapes)
print(f"Total area: {total:.2f}")

Best Practices

1. Use composition instead of inheritance when appropriate

class Engine:
    def __init__(self, power):
        self.power = power
    
    def start(self):
        return "Engine started"

class Car:
    def __init__(self, brand, engine):
        self.brand = brand
        self.engine = engine # Composition instead of inheritance
def start(self):
        return f"{self.brand}: {self.engine.start()}"

2. Redefine methods meaningfully

class Animal:
    def __init__(self, name):
        self.name = name
    
    def __str__(self):
        return f"Animal: {self.name}"
    
    def __repr__(self):
        return f"Animal('{self.name}')"

class Dog(Animal):
    def __str__(self):
        return f"Dog: {self.name}"
    
    def __repr__(self):
        return f"Dog('{self.name}')"

3. Use isinstance() for type checking

def handle_animal(animal):
    if isinstance(animal, Dog):
        return f"Walking the dog {animal.name}"
    elif isinstance(animal, Cat):
        return f"Feeding the cat {animal.name}"
    else:
        return f"Caring for {animal.name}"

Inheritance and polymorphism are powerful Python tools that make code more organized, flexible, and easy to maintain. Using these concepts correctly allows you to create scalable and maintainable applications.

 

categories

  • Introduction to Python
  • Python Programming Basics
  • Control Structures
  • Data Structures
  • Functions and Modules
  • Exception Handling
  • Working with Files and Streams
  • File System
  • Object-Oriented Programming (OOP)
  • Regular Expressions
  • Additional Topics
  • General Python Base