Showing posts with label Object-Oriented Programming. Show all posts
Showing posts with label Object-Oriented Programming. Show all posts

Advanced Polymorphism

← Back to Home

 

๐Ÿง  Advanced Polymorphism in Python: Beyond the Basics

๐Ÿš€ Introduction

In basic polymorphism, we learned how different objects can respond to the same method. But advanced polymorphism digs deeper—into abstract classes, interfaces, and real-world design patterns that help us build scalable, extensible, and robust applications.

Whether you're a student wanting to level up your OOP skills or a professional working on large-scale systems, understanding these advanced concepts can make your Python code more powerful and elegant.


๐Ÿ” Recap: What is Polymorphism?

Polymorphism lets objects of different classes be treated through a common interface, typically using shared method names. Python makes this easy with dynamic typing, but real power comes when we structure our code intentionally.


๐Ÿ” 1. Abstract Base Classes (ABCs)

In Python, abstract base classes define a blueprint for other classes. They're used when you want to enforce a common interface without writing full implementations.

from abc import ABC, abstractmethod

class Animal(ABC):
    @abstractmethod
    def speak(self):
        pass

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

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

✅ Benefits:

  • Forces consistency across subclasses.

  • Useful in larger codebases or APIs.

  • Enables polymorphism with safety—you can't instantiate an incomplete class.


๐Ÿงฉ 2. Interfaces via Abstract Classes

Python doesn’t have formal “interfaces” like Java or C#, but ABCs can simulate this behavior.

class Flyable(ABC):
    @abstractmethod
    def fly(self):
        pass

class Bird(Flyable):
    def fly(self):
        print("Bird is flying!")

class Drone(Flyable):
    def fly(self):
        print("Drone is flying!")

Now both Bird and Drone are interchangeable in any code that expects a Flyable.


⚙️ 3. Polymorphism with Composition and Delegation

Polymorphism doesn’t always require inheritance. With composition, we can combine behaviors in a modular way.

class Engine:
    def start(self):
        print("Engine started")

class Car:
    def __init__(self):
        self.engine = Engine()

    def start(self):
        self.engine.start()

Here, Car behaves polymorphically by delegating behavior to Engine.


๐Ÿง  4. Function and Method Overloading (Workarounds in Python)

Python doesn't support traditional method overloading like Java or C++, but you can simulate it:

class Calculator:
    def add(self, a, b=None):
        if b is not None:
            return a + b
        return sum(a)

calc = Calculator()
print(calc.add(5, 10))     # 15
print(calc.add([1, 2, 3])) # 6

This is polymorphism through conditional logic, handling different input types flexibly.


๐Ÿ› ️ 5. Real-World Use: Strategy Pattern with Polymorphism

The Strategy Pattern uses polymorphism to switch behaviors at runtime.

class PaymentStrategy(ABC):
    @abstractmethod
    def pay(self, amount):
        pass

class CreditCardPayment(PaymentStrategy):
    def pay(self, amount):
        print(f"Paid {amount} using Credit Card")

class PayPalPayment(PaymentStrategy):
    def pay(self, amount):
        print(f"Paid {amount} using PayPal")

class Checkout:
    def __init__(self, strategy: PaymentStrategy):
        self.strategy = strategy

    def process_payment(self, amount):
        self.strategy.pay(amount)

checkout = Checkout(CreditCardPayment())
checkout.process_payment(100)  # Paid 100 using Credit Card

This makes the system flexible, testable, and easy to extend with new payment types.


✅ Summary of Advanced Concepts

Concept Use Case
Abstract Base Classes Define strict interfaces
Interface Simulation Replace formal interfaces in Python
Composition & Delegation Preferable to deep inheritance hierarchies
Conditional Overloading Handle multiple input types or formats
Strategy Pattern Swap behaviors at runtime

๐ŸŽฏ Final Thoughts

Advanced polymorphism in Python is less about fancy syntax and more about intentional design. By combining abstract classes, interfaces, and composition, you can create systems that are not only powerful but also easy to extend, test, and maintain.

Whether we are building a payment system, a plugin framework, or a simulation engine—advanced polymorphism is our friend.

Python Inheritance

← Back to Home

 

๐Ÿ Inheritance in Python (Made Simple)

Inheritance is one of the most important concepts in Object-Oriented Programming (OOP). It allows a class to use the properties and methods of another class.

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


Think of it like a family: a child can inherit features from their parents.

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.

 In programming, a class (child) can inherit features (methods and variables) from another class (parent).

For more on Python classes, check out our post on Python Classes and Objects.


✅ Why Use Inheritance?

  • To reuse code.

  • To make the program easier to manage.

  • To follow the DRY principle (Don't Repeat Yourself).


๐Ÿงฑ Basic Syntax

class Parent:
    # parent class
    pass

class Child(Parent):
    # child class that inherits from Parent
    pass

๐Ÿ“˜ Example: Simple Inheritance

# Parent class
class Animal:
    def speak(self):
        print("I am an animal")

# Child class
class Dog(Animal):
    def bark(self):
        print("Woof!")

# Creating object of Dog
my_dog = Dog()

my_dog.speak()  # Inherited from Animal
my_dog.bark()   # Defined in Dog

๐Ÿ” Output:

I am an animal
Woof!

Here, the Dog class inherits the speak() method from the Animal class. It also has its own method called bark().


๐Ÿ“˜ Example 2: Inheriting from a Person Class

Let’s create a simple example where a Student class inherits from a Person class.

๐Ÿ‘จ‍๐Ÿ‘ฉ‍๐Ÿ‘ง‍๐Ÿ‘ฆ Step 1: Create the Parent Class

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

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

# Creating an object of Person
x = Person("Steve", "Tendulkar")
x.printname()

๐Ÿ” Output:

Steve Tendulkar

๐Ÿง’ Step 2: Create the Child Class

# Child class that inherits from Person
class Student(Person):
    pass  # No additional code, just inheriting everything from Person

# Creating an object of Student
x = Student("Mike", "Olsen")
x.printname()

๐Ÿ” Output:

Mike Olsen

๐Ÿ“ Note:
The pass keyword is used when you don't want to add any extra functionality to the child class. The Student class automatically gets all the properties and methods from the Person class.



๐Ÿ”„ Types of Inheritance in Python

  1. Single Inheritance – One child inherits from one parent.

  2. Multiple Inheritance – One child inherits from multiple parents.

  3. Multilevel Inheritance – A child inherits from a parent, and another child inherits from that child.

  4. Hierarchical Inheritance – Multiple children inherit from one parent.

  5. Hybrid Inheritance – A mix of any of the above types.


๐Ÿงช Example: Multiple Inheritance

class Father:
    def skill(self):
        print("Good at driving")

class Mother:
    def talent(self):
        print("Good at cooking")

class Child(Father, Mother):
    def hobby(self):
        print("Loves painting")

c = Child()
c.skill()
c.talent()
c.hobby()

๐Ÿ” Output:

Good at driving
Good at cooking
Loves painting

๐Ÿ’ก Important Points

  • The super() function is used to call methods from the parent class.

  • Inheritance makes your code organized and reusable.

  • If both parent and child have the same method, the child’s method will override the parent’s method.


๐Ÿ›  Using super() Example

class Animal:
    def speak(self):
        print("Animal speaks")

class Dog(Animal):
    def speak(self):
        super().speak()
        print("Dog barks")

d = Dog()
d.speak()

๐Ÿ” Output:

Animal speaks
Dog barks

๐ŸŽฏ Conclusion

Inheritance helps us write cleaner and more efficient code. Once we understand it, we can build complex applications more easily by reusing and extending existing code.

For more on Python classes, check out our post on Python Classes and Objects.

Python Classes and Objects

← Back to Home


๐Ÿ”น Classes and Objects in Python

Python is an object-oriented programming (OOP) language. This means it allows you to create and use classes and objects—which helps you organize and reuse code easily.



๐Ÿ”ธ What is a Class?

A class is like a blueprint for creating objects. Think of a class as a design for a car. It defines what a car is (wheels, engine, doors), but it's not a real car yet.

A class is a code template for creating objects. 

Objects have member variables and have behavior associated with them. 

In python, a class is created by the keyword class.

Example:

class Car:
    # attributes and methods go here
    pass


๐Ÿ”ธ What is an Object?

An object is a real-world instance of a class. If a class is the blueprint, then an object is the actual car built using that blueprint.

Example:

my_car = Car()

Now my_car is an object of the Car class.



๐Ÿ”ธ Let’s Build a Real Example

Let’s create a class that represents a Person with a name and age, and a method to display their info.

✅ Example:

class Person:
    def __init__(self, name, age):
        self.name = name      # attribute
        self.age = age        # attribute

    def greet(self):          # method
        print(f"Hello, my name is {self.name} and I am {self.age} years old.")

# Creating objects
person1 = Person("Surya", 25)
person2 = Person("Pawan", 30)

# Calling methods
person1.greet()
person2.greet()

๐Ÿ’ก Output:

Hello, my name is Surya and I am 25 years old.
Hello, my name is Pawan
and I am 30 years old.

๐Ÿ”ธ Breaking It Down

Part Description
class Person: Defines a class called Person
__init__ A special method called a constructor; runs when you create an object
self Refers to the current object (must be the first parameter in methods)
self.name = name Assigns the input to the object's attribute
greet() A method that prints a message using the object’s data

๐Ÿ”ธ Another Example: A Simple Bank Account

class BankAccount:
    def __init__(self, owner, balance):
        self.owner = owner
        self.balance = balance

    def deposit(self, amount):
        self.balance += amount
        print(f"{amount} deposited. New balance: {self.balance}")

    def withdraw(self, amount):
        if amount <= self.balance:
            self.balance -= amount
            print(f"{amount} withdrawn. New balance: {self.balance}")
        else:
            print("Insufficient balance!")

# Create an account
account = BankAccount("John", 1000)

# Use the methods
account.deposit(500)
account.withdraw(300)
account.withdraw(1500)

๐Ÿ’ก Output:

500 deposited. New balance: 1500
300 withdrawn. New balance: 1200
Insufficient balance!

๐Ÿ”š Summary

  • A class defines the structure and behavior (attributes and methods).

  • An object is a real example of the class.

  • Use __init__ to initialize object attributes.

  • Use self to refer to the current object inside the class.

  • Classes help keep your code organized, reusable, and clean.


Featured Post

Extra Challenge: Using References Between Documents

  ๐ŸŽฏ ๐Ÿ’ก Extra Challenge: Using References Between Documents Here's an  Extra Challenge  designed to build on the original MongoDB mod...

Popular Posts