DEV Community

Sandeep
Sandeep

Posted on • Edited on

Object-Oriented Programming in Python : Part 2

3. Polymorphism

The term 'polymorphism' comes from the Greek language and means 'something that takes on multiple forms.'

Polymorphism refers to a subclass's ability to adapt a method that already exists in its superclass to meet its needs. To put it another way, a subclass can use a method from its superclass as is or modify it as needed.

class Academic(Book):
    def __init__(self, title, quantity, author, price, branch):
        super().__init__(title, quantity, author, price)
        self.branch = branch

    def __repr__(self):
        return f"Book: {self.title}, Branch: {self.branch}, Quantity: {self.quantity}, Author: {self.author}, Price: {self.get_price()}"
Enter fullscreen mode Exit fullscreen mode

The Book superclass has a specific method called repr. This method can be used by subclass Novel so that it is called whenever an object is printed.

The Academic subclass, on the other hand, is defined with its own repr special function in the example code above. The Academic subclass will invoke its own method by suppressing the same method present in its superclass, thanks to polymorphism.

novel1 = Novel('Two States', 20, 'Chetan Bhagat', 200, 187)
novel1.set_discount(0.20)

academic1 = Academic('Python Foundations', 12, 'PSF', 655, 'IT')

print(novel1)
print(academic1)
Enter fullscreen mode Exit fullscreen mode

Output:

Book: Two States, Quantity: 20, Author: Chetan Bhagat, Price: 160.0
Book: Python Foundations, Branch: IT, Quantity: 12, Author: PSF, Price: 655
Enter fullscreen mode Exit fullscreen mode

4. Abstraction

Abstraction isn't supported directly in Python. Calling a magic method, on the other hand, allows for abstraction.

If an abstract method is declared in a superclass, subclasses that inherit from the superclass must have their own implementation of the method.

A superclass's abstract method will never be called by its subclasses. But the abstraction aids in the maintenance of a similar structure across all subclasses.

In our parent class Book, we have defined the repr method. Let's make that method abstract, forcing every subclass to compulsorily have its own repr method.

from abc import ABC, abstractmethod


class Book(ABC):
    def __init__(self, title, quantity, author, price):
        self.title = title
        self.quantity = quantity
        self.author = author
        self.__price = price
        self.__discount = None

    def set_discount(self, discount):
        self.__discount = discount

    def get_price(self):
        if self.__discount:
            return self.__price * (1-self.__discount)
        return self.__price

    @abstractmethod
    def __repr__(self):
        return f"Book: {self.title}, Quantity: {self.quantity}, Author: {self.author}, Price: {self.get_price()}"


class Novel(Book):
    def __init__(self, title, quantity, author, price, pages):
        super().__init__(title, quantity, author, price)
        self.pages = pages


class Academic(Book):
    def __init__(self, title, quantity, author, price, branch):
        super().__init__(title, quantity, author, price)
        self.branch = branch

    def __repr__(self):
        return f"Book: {self.title}, Branch: {self.branch}, Quantity: {self.quantity}, Author: {self.author}, Price: {self.get_price()}"


novel1 = Novel('Two States', 20, 'Chetan Bhagat', 200, 187)
novel1.set_discount(0.20)

academic1 = Academic('Python Foundations', 12, 'PSF', 655, 'IT')

print(novel1)
print(academic1)
Enter fullscreen mode Exit fullscreen mode

In the above code, we have inherited the ABC class to create the Book class. We've made the repr method abstract by adding the @abstractmethod decorator.

While creating the Novel class, we intentionally missed the implementation of the repr method to see what happens.

Output:

Traceback (most recent call last):
  File "C:\Users\ashut\Desktop\Test\hello\test.py", line 40, in <module>
    novel1 = Novel('Two States', 20, 'Chetan Bhagat', 200, 187)
TypeError: Can't instantiate abstract class Novel with abstract method __repr__
Enter fullscreen mode Exit fullscreen mode

We get a TypeError saying we cannot instantiate object of the Novel class. Let's add the implementation of the repr method and see what happens now.

class Novel(Book):
    def __init__(self, title, quantity, author, price, pages):
        super().__init__(title, quantity, author, price)
        self.pages = pages

    def __repr__(self):
        return f"Book: {self.title}, Quantity: {self.quantity}, Author: {self.author}, Price: {self.get_price()}"
Enter fullscreen mode Exit fullscreen mode

Output:

Book: Two States, Quantity: 20, Author: Chetan Bhagat, Price: 160.0
Book: Python Foundations, Branch: IT, Quantity: 12, Author: PSF, Price: 655
Enter fullscreen mode Exit fullscreen mode

Now it works fine.

Method Overloading:

The concept of method overloading is found in almost every well-known programming language that follows object-oriented programming concepts. It simply refers to the use of many methods with the same name that take various numbers of arguments within a single class.

Let's now understand method overloading with the help of the following code:

class OverloadingDemo:
    def add(self, x, y):
        print(x+y)

    def add(self, x, y, z):
        print(x+y+z)


obj = OverloadingDemo()
obj.add(2, 3)
Enter fullscreen mode Exit fullscreen mode

Output:

Traceback (most recent call last):
  File "C:\Users\ashut\Desktop\Test\hello\setup.py", line 10, in <module>
    obj.add(2, 3)
TypeError: add() missing 1 required positional argument: 'z'
Enter fullscreen mode Exit fullscreen mode

You're probably wondering why this happened. As a result, the error is displayed because Python only remembers the most recent definition of add(self, x, y, z), which takes three parameters in addition to self. As a result, three arguments must be passed to the add() method when it is called. To put it another way, it disregards the prior definition of add().

Thus, Python doesn't support Method Overloading by default.

Method Overriding:

When a method with the same name and arguments is used in both a derived class and a base or super class, we say that the derived class method "overrides" the method provided in the base class.

When the overridden method gets called, the derived class's method is always invoked. The method that was used in the base class is now hidden.

class ParentClass:
    def call_me(self):
        print("I am parent class")


class ChildClass(ParentClass):
    def call_me(self):
        print("I am child class")

pobj = ParentClass()
pobj.call_me()

cobj = ChildClass()
cobj.call_me()
Enter fullscreen mode Exit fullscreen mode

Output:

I am parent class
I am child class
Enter fullscreen mode Exit fullscreen mode

In the above code, when the call_me() method was called on the child object, the call_me() from the child class was invoked. We can invoke the parent class's call_me() method from the child class using super(), like this:

class ParentClass:
    def call_me(self):
        print("I am parent class")


class ChildClass(ParentClass):
    def call_me(self):
        print("I am child class")
        super().call_me()

pobj = ParentClass()
pobj.call_me()

cobj = ChildClass()
cobj.call_me()
Enter fullscreen mode Exit fullscreen mode

Output:

I am parent class
I am child class
I am parent class
Enter fullscreen mode Exit fullscreen mode

Wrapping Up:

In this article, we covered what classes and objects mean. We also covered the four pillars of the Object-Oriented Programming.

Apart from that we also touched two important topics – Method Overloading and Method Overriding.

Thanks for reading!

Object-Oriented Programming in Python : Part 1

Top Websites to learn Python

How to install python in windows 10

Python cheat sheet

Best IDE's for Python

Top comments (0)