This is a guide for developers who want to get a deeper knowledge of Python. You can find Python classes for beginners in this article.

This guide will cover the following:

  1. Inheritance
  2. Types of inheritance
  3. Polymorphism
  4. Encapsulation
  5. Types of members

Python Classes Advanced Guide

Inheritance

Inheritance in OOP is the ability of one class to derive other class properties( variables or functions). Inheritance is a very strong concept as it offers reusability of the code as you won’t need to start each code from scratch where you can use the same code and add as many features as your application needs. Also, it allows subclasses from the child class to inherit from the parent class e.g if class Fruit inherits from class Food all the classes that inherit from class Fruit can also inherit from the class Food. You let a class inherit from another by inserting the name of the parent class within brackets() after you define the second class with the following syntax class Fruit(Food):. Let’s have some basic example for inheritance:

Code:

class Food:
    def __init__(self, name): 
        self.name = name 
   
    def getName(self): 
        return self.name
    
    def isFresh(self):
        return True
    
class Fruit(Food):
    
    def isFresh(self):
        return False

food =  Food("Meat")
print(food.getName(),food.isFresh())

fruit = Fruit("Apple")
print(fruit.getName(),fruit.isFresh())

Output:

Meat True
Apple False

Explanation:

As you can see, when we applied the mentioned syntax for inheriting the subclass or the child class Fruit has the ability to inherit from the base class or the parent class Food, so it inherited the constructor method for creating the name and the getName method to return the name.

Types of inheritance

Single inheritance

Single inheritance gives the ability to a derived class or child class to inherit all the properties of a single parent class. Let’s see an example:
Python Classes Explained

Code:

class Food:
    def isFresh(self):
        print("Yes it's fresh")

    
    
class Fruit(Food):
    def weight(self):
        print("Weight is 10 kilos")
    
fruit = Fruit()
fruit.isFresh()
fruit.weight()

Output:

Yes it's fresh
Weight is 10 kilos

Explanation:

In this type of inheritance, the class Fruit has inherited the method in the class food and reused it when an object of the class Fruit was created.

Multiple inheritances

In this type of inheritance, the child class has the ability to inherit from various parent classes. Using the following syntax class child(parentclass1,parentclass2), the child class can inherit the properties of both parentclass1&2 and more depending on your application. Let’s see an example:
Python Classes Inheritance

Code:

class Food:
    def isFresh(self):
        print("Yes,it's fresh")
class Menu:
    def isAvailable(self):
        print("Yes,it's available")
class Fruit(Food,Menu):
    pass

fruit = Fruit()
fruit.isFresh()
fruit.isAvailable()

Output:

Yes, it's fresh
Yes, it's available

Explanation:

You can see the child class Fruit inherited both the methods found in the parent classes Food & Menu.

Multilevel inheritance

In this type of inheritance, the child class has another child class that inherits from it and in this case, you can call it a grandchild class or call the base class grandparent. It’s the same as the relationship between a son and his grandfather. In this case, the child class can inherit from both parent and grandparent classes. Let’s see an example:
Python Multilevel Inheritance

Code:

class Family:
   family_name = ""

class Middle(Family):
    middle_name = ""

class Name(Middle):
    name = ""
    def fullName(self):
        print(self.name, self.middle_name,self.family_name)

myname = Name()
myname.family_name = "Patrick"
myname.middle_name = "Robert"
myname.name = "John"
myname.fullName()

Output:

John Robert Patrick

Explanation:

As you can see the class Middle inherits from the class Family so it has access to its properties and as the class Name inherits from the class Middle then by order it inherits from the class Family also. As we can see it has accessed the variable family_name from the grandparent class.

Hierarchical inheritance

In this type of inheritance, one parent or base class has more than one child class inheriting from it where they all can inherit all the properties of the parent class. Let’s see an example:
Python Hierarchical Inheritance

Code:

class Fruit:
   def approve(self):
       print("Yes, it belongs to Fruit class")

class Apple(Fruit):
    def anApple(self):
        print("yes, it also belongs to Apple class")
class Orange(Fruit):
    def anOrange(self):
        print("yes, it also belongs to Orange class")

apple = Apple()
orange = Orange()

apple.approve()
apple.anApple()
orange.approve()
orange.anOrange()

Output:

Yes, it belongs to Fruit class
yes, it also belongs to Apple class
Yes, it belongs to Fruit class
yes, it also belongs to Orange class

Explanation:

In this type of inheritance besides each class’s own functions, we can see that classes Apple & Orange also inherited the class Fruit and had access to the functions presented in it.

Polymorphism

Polymorphism means having many forms or states of the same thing. So in programming polymorphism means having the same function name but are used differently and you can see this in Python for example with the function len() where it can be used with strings, arrays, and a lot of other concepts. That’s the concept of polymorphism where we can reuse the name of the function but with different usage and output and that can be applied in classes as well with all its concepts.

Polymorphism with class functions

As many classes as you have some of these classes can have the same function names but with different outputs, each function gives its unique output when an instance of its class is made now the program knows that you are calling this function of that class. Let’s see an example:

Code:

class Orange:
    def color(self):
        print("it's color is orange")
    def weight(self):
        print("it weighs 200 grams")    
class Apple:
    def color(self):
        print("it's color is red")
    def weight(self):
        print("it weighs 250 grams")
orange = Orange()
apple = Apple()

orange.color()
orange.weight()
apple.color()
apple.weight()

Output:

it's color is orange
it weighs 200 grams
it's color is red
it weighs 250 grams

Explanation:

As you can see that both classes Orange and Apple have the same function names color & weight. But as Python supports Polymorphism it distinguishes between each of them and what output they give based on whether they called on which instance either of the Orange class instance or Apple class instance.

Polymorphism with inherited functions

Also, polymorphism concept can be applied to inherited functions although the child class inherited the functions presented in the parent class, polymorphism allows you to define functions with the same name of the functions presented in the parent class and modify it and that is called Function Overriding. And that helps us with modifying some inherited functions that might need changes to fit the child class. Let’s see an example:

Code:

class Fruit:
    def color(self):
        print("Most fruits have a green color")

class Orange:
    def color(self):
        print("but Orange has orange color")   
class Apple:
    def color(self):
        print("and Apple has red color")
fruit = Fruit()
orange = Orange()
apple = Apple()

fruit.color()
orange.color()
apple.color()

Output:

Most fruits have a green color
but Orange has orange color
and Apple has red color

Explanation:

Applying polymorphism in the above code lets you fit the inherited function in the way you want for both of the child classes where Function Overriding took a place when the inherited function was defined again within reach of the child classes. So you can see when an instance is created of the Orange & Apple classes each color() function gives an output depending on which instance it’s called at.

Encapsulation

Encapsulation is one of the main concepts of OOP where it helps you to keep your data safe from any modifications or changes. So it’s like you created an object of a class Encapsulations allows you to modify variables of that object only using functions presented in that object too.

Types of members

Protected members

These members shouldn’t be accessed from outside the class however nothing can stop you from doing that, also they can be accessed from the class itself or any of its subclasses. But Python doesn’t have a Protected keyword however this can still be achieved by putting an underscore before the member like this _a, this is now a protected member. Let’s see an example:

Code:

class Fruit:
     #name as a public member
     name = "Banana"
     #name as a protected member
     _name = "Orange"
class Orange(Fruit):
    pass

orange = Orange()

print(orange.name)
print(orange._name)

Output:

Banana
Orange

Explanation:

As you can see both public members and protected members can be directly accessed within a subclass or a child class of the base class they are defined at.

Private members

These types of members are like the protected ones but they cannot be defined outside the class and they cannot even get access through the subclasses from the base class they are defined within. Also, Python doesn’t have the private keyword but still, this can be applied by adding two underscores before the member name like this __a. Let’s see if we tried to access a private member outside the class:

Code:

class Fruit:
     #name as a public member
     name = "Banana"
     #name as a protected member
     _name = "Orange"
     #name as a private member
     __name = "Apple"
fruit = Fruit()
print(fruit.name)
print(fruit._name)
print(fruit.__name)

Output:

Banana
Orange
print(fruit.__name)
AttributeError: ‘Fruit’ object has no attribute ‘__name’

Explanation:

Here we can see the difference between protected and private members, although protected members shouldn’t be accessed from outside the class it’s doable. Unlikely with the private members they are forbidden to get accessed from outside the class.

Setters and getters

But you still have the ability to modify and access private members using getters and setters where it’s an indirect way to access private members where this is done within the class itself and the user only deals with setters and getters outside the class. And that is the ideal definition of Encapsulation where the data members of the class are only accessed using functions of the class and that takes place inside the class ONLY. Let’s see an example:

Code:

class Fruit:
    def __init__(self):
        self.__type = "Banana"
    
    def setType(self,type):
        self.__type = type

    def getType(self):
        print(self.__type)

fruit = Fruit()
fruit.getType()
fruit.setType("Orange")
fruit.getType()

Output:

Banana
Orange

Explanation:

You can see that the modifications and the printing of the private member are done through setType & getType functions.