Object oriented programming using python
Tags: python, oop, classes, 100daysofcode
Published: 2022-04-06 09:28:13

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e5ynuww3w65yzhlph250.png)
Python is a great programming language that supports Object Oriented Programming.

### **What is Object oriented programming?**
 This is a flexible, powerful paradigm where classes represent and define concepts while objects are instances of classes.<br>

###**Why use Object Oriented Programming?**

- It makes code more reusable so you don't have to repeat once 
 defined.

- Makes it easier to work with larger programs.

- Makes program easy to understand.

**A class** is a user-defined blueprint from which objects are created. 
Classes have _attributes_ and _methods_ associated with them and you can have _instances_ of a class when you create new, individual objects in a certain class.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7v6nta1rsfohrgzeyoon.png)
For example in the above diagram, we have a class that we have named _Fruit_.

Banana, apple, pineapple and strawberry are **instances** of the class Fruit.
**An instance** is an object that is built from a class and contains real data.

**Attributes** are the characteristics associated to a class or a certain instance of a class. Like in our example apple can have attributes: color(red) and texture(smooth)

**Methods** are functions that operate on the attributes of a specific instance of a class. In our _apple_ example ,we can have a **_cut_** method which turns it to pieces or **_eat_** method which reduces the apple size with every bite.

###**Creating and defining classes in Python**
We create and define classes in Python similar to how we define functions.
Start with the **_class_** keyword, followed by the name of the class and a colon. Class names start with a capital letter. After the class definition line is the class body, indented to the right.
```python
class Fruit:
  color=" "
  texture=" "
```
We can set the attributes of our class instance by accessing them using dot notation.
Dot notation can be used to set or retrieve object attributes as well as call methods associated with them.
```python
apple.color="red"
apple.texture="smooth"
```
We created a **_Fruit_** instance called _**apple**_ and set the color and texture attributes. Another instance of Fruit can be created and set different attributes.
```python
pineapple.color="brown"
pineapple.texture="rough"
```

###**Special methods**
The examples above are classes and objects in their simplest form and are not really useful in real life applications.

Special methods start and end with **two underscore characters**.
There are many special methods that you can use to customize classes in Python.

 
All classes have a special method **__ init __()** ,which is always executed when the class is being used to create a new object. It is used to assign values to object properties or other operations that are necessary to do when the object is being created.
```python
class Fruit:
  def __init__(self,name,color,texture):
    self.name=name
    self.color=color
    self.texture=texture

fruit1=Fruit("apple","red","smooth")

print(fruit1.color)
print(fruit1.texture)
print(fruit1.name)
```
Output:
```python
red
smooth
apple
```
> The _self_ parameter is a reference to the current instance of 
 the class, and is used to access variables that belong to the 
 class.

There is also a  **__ str __()** special method which returns the output in a string format.
```python
class Fruit:
  def __init__(self,name,color,texture):
    self.name=name
    self.color=color
    self.texture=texture
    

  
  def __str__(self):
    return f"{self.name} is a fruit and its {self.color} in color and its {self.texture}"
  
fruit2=Fruit("Apple","red","smooth")
print(fruit2)
```
Output:
```python
Apple is a fruit and its red in color and its smooth
```

An example of method in our Fruit class is as shown below:
```python
class Fruit:
  def __init__(self,name,color,texture):
    self.name=name
    self.color=color
    self.texture=texture

  def fruity(self):
    return f"{self.name} is {self.color} in color and {self.texture} "

  def describe(self,taste):
    return f"{self.name} is {taste}"


fruit1=Fruit("apple","red","smooth")
print(fruit1.fruity())

print(fruit1.describe("sweet"))
```
Output:
```python
apple is red in color and smooth 
apple is sweet
```
_Fruity_ and _describe_ are methods in our Fruit class.

There are several key concepts in Object Oriented Programming.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ixncuvhu5kw3tanu2r5g.png)
 

## **Inheritance**
In object-oriented programming, the concept of inheritance allows you to build relationships between objects, group together similar concepts and reduce code duplication.

A **parent class** is the class being inherited from.Any class can be a parent class, so the syntax is the same as creating any other class.

A **child class** is the class that inherits from another class.A child class inherits the properties and methods from its parent but you can also add other properties.
When creating a child class, the name of the parent class is set as the parameter so that it can inherit its functionality.

> To keep the inheritance of the parent's __init__() function, 
  add a call to the parent's __init__() function
```python
class Person:
  def __init__(self,name,age):
    self.name = name
    self.age = age

  def display(self):
    print(self.name+" is "+str(self.age)+" years old")

#child class
class Student(Person):
  def __init__(self,name,age,admission,form):
    self.admission=admission
    self.form = form

    # invoking the __init__ of the parent class 
    Person.__init__(self,name,age)


#Creating an object
Aziz = Student("Abdul Aziz","22","6325",4)

Aziz.display()

Output
>>> Abdul Aziz is 22 years old
```
From the above example, we have created a child class _**Student**_ from the parent class  _**Person**_  and it inherits the attributes _**name and age**_ and method _**display**_ from its parent.Although, we have added other attributes _**admission and form**_ to our child class.
> Python also has a super() function that will make the child class inherit all the methods and properties from its parent

## **Encapsulation**
This concept allows us to restrict access to methods and variables. This prevents data from direct modification. In Python, we denote private attributes using **underscore** which can either be single _ or double __.
```python
class Computer:

    def __init__(self):
        self.__maxprice = 900

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

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

c = Computer()
c.sell()

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

# using setter function
c.setMaxPrice(1000)
c.sell()
```
Output:
```python
Selling Price: 900
Selling Price: 900
Selling Price: 1000
```
In the above program ,we have defined a **_computer_** class whereby the__init__() method is for storing the maximum selling price of computer.
We try to set max price outside and it cannot be reflected since its a private variable __maxprice  hence using a setter function to change the price.

## **Polymorphism**
The word polymorphism means having many forms. In programming, polymorphism means the same function name (but performing different activities) which allows flexibility.

```python
class India():
    def capital(self):
        print("New Delhi is the capital of India.")
 
    def language(self):
        print("Hindi is the most widely spoken language of India.")
 
    def type(self):
        print("India is a developing country.")
 
class USA():
    def capital(self):
        print("Washington, D.C. is the capital of USA.")
 
    def language(self):
        print("English is the primary language of USA.")
 
    def type(self):
        print("USA is a developed country.")
 
obj_ind = India()
obj_usa = USA()
for country in (obj_ind, obj_usa):
    country.capital()
    country.language()
    country.type()
```
Output:
```python
New Delhi is the capital of India.
Hindi is the most widely spoken language of India.
India is a developing country.
Washington, D.C. is the capital of USA.
English is the primary language of USA.
USA is a developed country.
```
We have created two classes  **_India_**  and  **_USA_** .They have similar structure and methods **_capital,language,type_** although they are not linked in any way, we are able to use a _for loop_  to iterate them through a common  _country variable_.
This is made possible by polymorphism.

For more understanding of polymorphism concept here are some links:
https://www.geeksforgeeks.org/polymorphism-in-python/
https://www.programiz.com/python-programming/polymorphism