Object Oriented Programming with Python
Tags: python, beginners, programming, software
Published: 2022-02-28 10:40:30

A look into the Object Oriented concepts using Python after understanding [Data Structures and Algorithms with Python](https://dev.to/collins42rono/introduction-to-data-structures-and-algorithms-with-python-1k0h)

## Introduction to Programming Paradigms

While writing a program, there are various features a program can contain. These different features are described as programming paradigms. Various programing paradigms are: functional programming, logical programming, imperative programming and then there is object oriented programming.

Programming languages support most of these paradigms and therefore it depends on the needs of the programmer to choose what works best for the current problem being solved.

In Object Oriented Programming, attributes of an object are first designed into a class, then an instance of the class which is an object is created. Take for instance a book which will contain name or title of the book, author, and number of pages. They are all attributes of a book which is considered a class. An instance of this book may be "Python101" by "Mike Driscoll" with 100 pages. This is our object since it is an instance of our class book.

Let's look at another example:

```
class Car():
    def __init__(self, make, model):
        self.make = make
        self.model= model

nissan1 = Car("Nissan", "Altima")
print(nissan1.make)
```
We'll dive deeper into the structure of the code but first let's understand it.

`OUPUT`
```
Nissan
```

The above example represents a class Car which has attributes make and model.
Outside the class we have instantiated an object named `nissan1` and gave it make and model `Nissan` and `Altima`. The `print` method outputs the make of the car.


## Main OOP concepts Python

We have looked at the objects and classes in Python. With a class being more of a blueprint of an object and an object an instance of a class. The class Car in the above example uses a keyword `class` and the object `nissan1` uses the defined class `Car` to create an instance of `Car`.

Also notice the `__init__` keyword. This is a constructor similar to the ones in Java and it uses the keyword `self` to initialize attributes of our class.

Object Oriented Programming also allows for other concepts with classes and objects i.e., `Inheritance`, `Encapsulation`, and `Polymorphism`


**Inheritance**
Inheritance allows one class `child class` to inherit properties of another already defined class `parent class`. This enables reusability of code which is already written in one class to be used without redundancy of code.

```
# parent class
class Person(object):
  
    #the constructor
    def __init__(self, name, age):
        self.name = name
        self.age= age
  
    def display(self):
        print(self.name)
        print(self.age)
          
    def details(self):
        print("My name is {}".format(self.name))
        print("age: {}".format(self.age))
      
# child class. Notice the parent class (Person)
class Employee(Person):
    def __init__(self, name, age, salary, post):
        self.salary = salary
        self.post = post
  
        # invoking the parent class
        Person.__init__(self, name, age)
          
    def details(self):
        print("My name is {}".format(self.name))
        print("Age: {}".format(self.age))
        print("Post: {}".format(self.post))
  
  
# creation of an object variable or an instance
employee1 = Employee('Rahul', 45, 200000, "Intern")
  
# calling a function of the class Person using
# its instance
employee1.display()
employee1.details()

```


**Polymorphism**

Polymorphism allows an object to take many forms

In the above example an object person can take the form `Person` or `Employee` since the child class inherits from the parent class.

```
class Book():
    def intro(self):
        print("I have a name")
        
    def pages(self):
        print("I have a number of pages")
        
class Novel(Book):
    def pages(self):
        print("Novels too have pages")
        
class drawingBook(Book):
    def pages(self):
        print("A drawing book must also have pages")
        
book1 = Book()
novel1 = Novel()
drawbook1 = drawingBook()

novel1.intro()
book1.intro()
drawbook1.intro()
```

`OUTPUT`

```
I have a name
I have a name
I have a name
```

The method used by the other books `Novel` and `drawingBook` come from the parent class `Book`



**Encapsulation**


Encapsulation allow restricted access to methods and variables in Python to prevent data from direct modification. This is achieved by using private attributes. In Python, we denote private attributes using underscore as the prefix i.e., single `_` or double `__`.

Let's have an example:


```
class Book:

    def __init__(self):
        self.__maxprice = 900

    def sell(self):
        print("Selling Price: {}".format(self.__maxprice))

    def setMaxPrice(self, price):
        self.__maxprice = price

book1= Book()
book1.sell()

# change the price
book1.__maxprice = 1000
book1.sell()

# using setter function
book1.setMaxPrice(1000)
book1.sell()

```

OUTPUT:

```
Selling Price: 900
Selling Price: 900
Selling Price: 1000
```

`__maxprice` has been set to a private .

The code
```
book1.__maxprice = 1000
book1.sell()
```
attempts to change the `maxprice` to 1000 but it doesn't change as seen in the second output because maxprice is set to private.

The setter function
```
book1.setMaxPrice(1000)
book1.sell()
```
is used to successfully used to change the max price to 1000.

```
Selling Price: 1000
```