DEV Community

Benny
Benny

Posted on • Updated on

Object-oriented Programming in Python šŸ

Object-oriented Programming (OOP) is a computer programming model that helps one organizes their software design around data, class, and object rather than functions and logic.
Just like you have Knowledge and can perform various methods, Objects have data and can perform various methods.

Class is the blueprint used to create a user-defined data structure. It holds the common attribute and behaviors of the object. For example, the class ā€œRideā€ will hold objects ā€œcarā€, ā€œplaneā€ and ā€œbikeā€.

Object is an instance of a class. It has both a property (variables) and behavior (methods). The python object ā€œCarā€ will have properties; ā€œmakeā€, ā€œmodelā€, ā€œfour_wheelsā€ and behaviors; ā€œstartā€, ā€œstopā€.

Method is the behavioral factor of the object. Modifying a method in the class ā€œRideā€ would affect all instances of it; ā€œcarā€, ā€œplaneā€, and ā€œbikeā€.

Instance is simply any object made from the class. An instance of the ā€œRideā€ class would contain real unique data. A class is like a form while an instance is a filled variation of that form.

It is good practice to identify all the objects you want to manipulate and how they relate among themselves. This is data modeling.

Principles of OOP

1. Encapsulation

State, variables, and methods should be private unless they are being declared public.

An object ā€œcarā€ of a class ā€œRideā€ can manage itself via methods ā€œstartā€ and other class ā€œHouseā€ cannot touch it expect
allowed to. We can only use the methods to communicate with our object. If we want another class ā€œHouseā€ to change the state of the ā€œcarā€ object, we have to create public methods ā€œover_ride_and_startā€ to modifies or invoke the start
variable. This connection is encapsulation.

2. Abstraction

Hide all implementation of the class from anything outside the class.

Our object should hide details and only expose relevant information to another object. Thus public method should be created so object can be called. The ā€œAl voice recognitionā€ may start our ā€œcarā€ object (in the ā€œRideā€ class) and open the ā€œLightsā€ object (in the ā€œHomeā€ class) without having access to the details of our car. This makes maintenance of
an extremely large database less daunting and lowers the chances of bugs.

3. Inheritance

Child class should have a mechanism that enables it to inherit behavior and properties from the parent class.

Reusability is the advantage here. Child class ā€œcarā€, ā€œboatā€ objects should acquire properties (ā€œhas_an_engineā€, ā€œcan_be_used_for_transportā€) from the parent class ā€œRideā€. However, they should have their own unique properties.

4. Polymorphism

Interfacing with objects and receive different forms or results.

This allows us to implement a class exactly as intended for the parent class. This prevents errors in types and each
sub-class keeps its own methods. Our class ā€œRideā€ has a speed method. Our child class; ā€œObjectā€, ā€œboatā€ and ā€œplaneā€ can utilize this method. However, they would each have their own iteration of the speed method.

OOP in Python šŸ

Let's Begin! šŸš€

Here is a Link to the notebook on my Github. You could download it and follow along.

Class is defined with the class keyword followed by the name of the class.

class Car:
    pass #This is also where subsequent code will eventually go.
Enter fullscreen mode Exit fullscreen mode

The pass acts as a place holder and thus prevents python from returning an error. At the moment, our car class is without attributes or methods. Let's instantiate our object class by calling the class.

car()
Enter fullscreen mode Exit fullscreen mode

Every instance of our class is stored in a new memory address. which means every instance of the Car class represents two different objects. Wanna try?

a = Car()
b = Car()
print (a == b)
Enter fullscreen mode Exit fullscreen mode

Our class has a docstring attribute called doc which holds the documentation of the object.

class Car:
    #this is the docstring and it gives a brief about the class
    """ A four-wheeled road vehicle that is powered by an engine car has four wheels"""

Car.__doc__
Enter fullscreen mode Exit fullscreen mode

Letā€™s make our class interesting by giving it attributes. There are two types; Class attributes and Instance attributes.
Every attribute in our class would be defined in a method called .init() with self as the first parameter. These are called instance attributes. However, class attributes are attributes that have the same value for all instances of that class. Hence it would be assigned outside the .init() method. All instances of car class (model and colour) are four-wheeled.

class Car:
    #Class attributes
    wheels = "four"
    def __init__(self, model, colour):
         self.model = model
         self.colour = colour
Enter fullscreen mode Exit fullscreen mode

Letā€™s give our instance attributes parameters values. šŸ§Ø

Toyota = Car("Toyota", "yellow")
kia = Car ("Kia", "black")
Ford = Car("ford", "blue")
Honda = Car("Honda", "brown")
Enter fullscreen mode Exit fullscreen mode

We have four Car instances with each having unique values. Letā€™s access the data in these attributes.

#instance attributes
Toyota.model
print(Toyota.model)

kia.colour
print(kia.colour)

#class attributes
Toyota.wheels
print(Toyota.wheels)

kia.wheels
print (kia.wheels)
Enter fullscreen mode Exit fullscreen mode

Like I mentioned all instances in a class have .wheels, .model and .colour. However, the values of the instances attributes (.model and colour) would differ; encapsulation and polymorphism. We can also update and modify the values in our instance without changing the values.

#modifying our attributes
Toyota.colour = "red" #previously yellow
print (Toyota.colour)

kia.wheels = "two" #previously four
print (kia.wheels)
Enter fullscreen mode Exit fullscreen mode

It worked!! šŸ˜Ž So objects are mutable.

Letā€™s look at instance methods. Just like .init(), the first parameter is also always self and is defined in our class. Letā€™s create two instance methods; speed and details.

class Car:
    wheels = "four"
    def __init__(self, model, colour):
         self.model = model
         self.colour = colour

    # Instance method
    def details(self):
        return f"this {self.model} is {self.colour}"

    # Another instance method
    def speed(self, speed):
        return f"This {self.model} is {speed} at top speed"

Enter fullscreen mode Exit fullscreen mode

Let's apply these new methods.

Toyota = Car("Toyota","yellow")
print (Toyota.details())

#Toyota.speed(280)
print (Toyota.speed(280))
Enter fullscreen mode Exit fullscreen mode

Letā€™s look at inheritance. Letā€™s say we want to add a new class ā€œengineā€. We canā€™t always specific the engine for each car. Letā€™s create a child class for it

class Hybrid_engine(Car):
    pass

class Gas_engine(Car):
    pass
Enter fullscreen mode Exit fullscreen mode

Now letā€™s instantiate these engines for the cars.

Toyota = Gas_engine("Toyota", "yellow")
kia = Gas_engine("kia", "black")
Honda = Gas_engine("Honda", "brown")
Ford = Hybrid_engine("Ford", "blue")
Enter fullscreen mode Exit fullscreen mode

Letā€™s try some basic functions.

print(type(Toyota))
print(isinstance(Toyota, Car))
print(type(Ford))
print (isinstance (Ford, Gas_engine))
#Toyota, Kia, Honda and Ford are all instance of Car 
#but Ford wouldnā€™t be in the Hypdrid engine child class instance.
Enter fullscreen mode Exit fullscreen mode

Thus, all objects created from the child class is an instance of the parent (car) but might not be in the same child class (Gas_engine and Hybrid_engine). Letā€™s give it the parentā€™s functionality specific to it (Inheritance)

class Hybrid_engine(Car):
    def speed(self, speed="210"):
        return f"{self.model} Speed; {speed}"

Ford = Hybrid_engine("Ford", "blue")
print (Ford.speed())
Enter fullscreen mode Exit fullscreen mode

A change in the parent class wouldnā€™t affect the child class.

class Car:
    wheels = "four"
    def __init__(self, model, colour):
         self.model = model
         self.colour = colour

    # Instance method
    def details(self):
        return f"this {self.model} is {self.colour}"

    # Another instance method
    def speed(self, speed):
        return f"This {self.model} is {speed} at top speed"

Toyota = Gas_engine("Toyota","yellow")
print (Toyota.speed(367))

#however ford wouldnā€™t get the change since we define his child class

Ford = Hybrid_engine ("Ford", "blue")
print (Ford.speed(467))
Enter fullscreen mode Exit fullscreen mode

However, if we didnā€™t want this to happen. We would need to use the .super built-in function for the child class. šŸ™ƒ

class Hybrid_engine (Car):
    def speed(self, speed="210"):
        return super().speed(speed)

Ford = Hybrid_engine ("Ford", "blue")
print (Ford.speed())
Enter fullscreen mode Exit fullscreen mode

Summary šŸŽ‰

In this article, we discussed Object-oriented Programming and the principles which govern it.

Then we looked at how to define a class, how to instantiate an object from a class, and giving this class some sought of documentation using .doc. Let's not forget we looked at an instance and class attributes and defining properties and behaviors of an object. We also discussed some function such as type(), isinstance() and super(). šŸš€

I hope you found this notebook helpful. Remember to share on your favorite social media so other folks can find it, too. Thanks šŸ‘

Top comments (0)