Python Object oriented programming(OOP)

Object-oriented programming is a structured way of representing and manipulating objects. Python supports the object-oriented programming paradigm. In object-oriented programming, codes are structured around objects that interact with each other through methods and attributes. The class houses the objects, methods, and attributes. The class provides a method to manipulate the attribute and method, all encompassed under a single object.

Let's describe some basic concepts in Python object-oriented programming.

Class: In Python, the class is at the center of object-oriented programming. The class provides a template or blueprint that defines the basic characteristics of a particular object. The class defines the attributes and methods that the object possesses.

Object: The object is described as the instance of the class. The class can produce as many objects as possible. The object can represent a real-world entity or abstract term that has behaviors and methods.

Attributes: The attribute is basically a variable. The attribute is the characteristic or features of the object instantiated from the class. 

Methods: The method is a function. The method describes the behavior of the object. The method interacts with the attribute to perform actions. 

Using the concept explained let's write a code. 

class Animal(object):
species = "mammals" #class attribute

def __init__(self, name): # special method
self.name = name # Instance attribute

def is_a_mammal(self, number_of_limbs): #Normal method
if number_of_limbs == 4:
print(f"The animal, {self.name}, is a mammal")
else:
print(f"The animal, {self.name}, is not a mammal")
pig = Animal("pig")
horse = Animal("horse")
hen = Animal("hen")
print(pig.species)

hen.is_a_mammal(2)

Let's explain the code as follows:

The class, Animal is made up of attributes and methods(functions). It is a template for creating objects (instances) of the Animal class.

species = "mammals"  represents the attribute of the class. All the instances of the class can use the class attribute. 

def__init__(self, name) is a magic method(special or dunder method) or a constructor that initializes the object. The self is an instance and the name is the argument created along with the instance, self.

def is_a_mammal(self, number_of_limbs) is a normal method. The regular method takes two parameters namely self (instance) and number_of_limbs. It checks if the number of limbs is equal to 4. If it is, it prints that the animal is a mammal; otherwise, it prints that the animal is not a mammal. 

pig = Animal("pig"), horse = Animal("horse") and hen = Animal("hen") are instances of the class Animal. The __init__ method is called to initialize each instance with a name

pig.species The attribute of the class can be accessed by the instances of the class using dot notation.

hen.is_a_mammal(2) calls the is_a_mammal method on the hen instance and passes 2 as the number_of_limbs argument. 

Output: "The animal, hen, is not a mammal.

Let's discuss the four major principles of object-oriented programming and the Pythonic way of applying them.

  • Inheritance
  • Encapsulation
  • Polymorphism
  • Abstraction

Inheritance: Inheritance is one of the most important principles in object-oriented programming. The inheritance principle allows one to create a new class that inherits the properties, attributes, and methods of another class. The new class is known as the derived class, while the class it is inherited from is the base class. 

Let's demonstrate how we can apply the inheritance principle.

class Rectangle():
def __init__(self, l, w):
self.l = l #instance attribute
self.w = w #instance attribute

def area(self):
return self.l * self.w

class Square(Rectangle):
def __init__(self, s):
super().__init__(s, s)

b = Square(5)
print(b.area())

The class rectangle is created. The class has two methods, the constructor method(__init__) and the normal method(area()). The constructor method takes two arguments l (length) and w (width), and assigns them as instance attributes self.l and self.w. The area method calculates and returns the area of the rectangle using the instance attributes self.l and self.w

The class square inherits the methods and attributes of the Rectangle class. The class has a constructor (__init__) that takes an argument, s . The super() function is used to call the constructor of the parent class (Rectangle). It passes the argument, s as l and w to replace the instance attribute of the parent class(self.l and self.w

Finally, an instance of the class Square is created with the parameter 5. The area method from the parent class is then used to find the area of the square using the instance of square b. 

The code explains the principle of inheritance. The Square instance was able to use the area method from the base class(Rectangle) because the methods were inherited by the Square class.

Encapsulation: Encapsulation is an important concept in object-oriented programming. It allows one to modify how data is accessed within the classes. 

The encapsulation principle is used to hide details from the outside. Encapsulation in Python hides attributes and methods within a class and they can only be accessed by a specific method.

Encapsulation can be implemented in Python using underscores. 

Let's use the double underscore to declare private characteristics as follows:

class Square():
def __init__(self, length):
self.__length = length
def area(self):
return self.__length * self.__length
my_square = Square(7)
print(f"The area of the square is {my_square.area()}")

#my_square.__length # This will result in an error

The Square class has a private attribute "__length". The length attribute can only be accessed through the class method(area). Attempting to access the private attribute "__length" from outside the class will result in an error. This illustrates the encapsulation principle. 

PolymorphismThe word polymorphism is derived by combining two Greek words: poly and morphs. Poly is interpreted as many, while morphs mean forms. So, literally, it can be interpreted as "many forms".

Polymorphism in Python object-oriented programming refers to the ability of different objects to respond to the same method in different ways. 

Let's use method overriding to illustrate how polymorphism works,

class Animal():
def sound(self):
pass
class Dog(Animal):
def sound(self):
return "Bark"
class Lion(Animal):
def sound(self):
return "Roar"
a = Dog()
b = Lion()
print(a.sound())
print(b.sound())

From the code, we created the Dog and Lion objects and called their 'sound' methods, which behave differently. That's polymorphism in a nutshell.

Abstraction: Abstraction can be demonstrated in Python by using abstract methods and classes. Abstraction is more like a program shielding complex implementation while exposing only the necessary parts to the user. 

Conclusion:

Object-oriented programming in Python provides a structured way of manipulating objects. Important concepts in Object-oriented programming are class, object, attributes, and methods. Important principles of object-oriented programming are abstraction, polymorphism, encapsulation, and inheritance.