OOPs
- Python is an object oriented programming language which contains data (attributes) and functions (methods). Python allows for the creation of reusable and modular code by modeling real-world entities.
Below are the key concepts of OOPs :
- Class: A blueprint for creating objects. It defines the attributes and methods that the objects will have.
- Object: An instance of a class. Objects hold data and interact with each other through methods.
- Encapsulation: Restricting access to certain details of an object and exposing only essential features.
- Inheritance: Allowing a class to inherit properties and methods from another class, enabling reusability.
- Polymorphism: Allowing different classes to define methods with the same name but different behavior.
- Abstraction: Hiding the implementation details and showing only the functionality to the user.
Let’s take deep dive in each concept one by one.
1. Class
- It defines the attributes (data) and methods (functions) that the objects created from the class will have. Classes are the foundation of Object-Oriented Programming (OOP) in Python, enabling the creation of reusable and modular code.
- To define a class, use the
class
keyword: a class is a user defined data type, where we give a name to the data type and This data type may contain variables inside of it with where each variable can having different data types.
- Class can have multiple Attributes and Methods inside of it.
1.1 Attributes : are a Variables that belong to the class or an instance of the class. If we modify a class variable through an instance, a new instance variable is getting created. This separates the modified value from the original class variable, which remains unchanged for other instances.
- Instance Attributes: Defined inside the constructor (
__init__
) and belong to each object. - Class Attributes: Shared across all instances of the class.
- Instance Attributes: Defined inside the constructor (
class Example: shared_attr = "I am class attribute." # Class attribute def __init__(self, value): self.instance_attr = value # Instance attribute
1.2 Methods : are a Functions defined within the class that describe the behaviour of the objects. below are the different types of methods :
- Instance Methods: Operate on instance attributes and use
self
as the first parameter. When you add a method to a class, we must have self as the first argument of that function. but when you call a function you don’t actually input self - Class Methods: Operate on class attributes and use
@classmethod
andcls
. - Static Methods: Don’t operate on instance or class attributes and use
@staticmethod
- Instance Methods: Operate on instance attributes and use
class Employee: def __init__(self, name, age): # Instance method self.name = name # Instance attribute self.age = age @classmethod def class_method(cls): #Class method print("This is a class method.") @staticmethod def static_method(): # Static method print("This is a static method.")
2. Object
To create an object, call the class as if it were a function. After creating a new object we can modify the object properties, also we can object properties or object.
e1 = Employee("Martha", 18) #Create Instance of Employee class e1.age = 40 #Modify Properties del e1.age #Delete object property del e1 #Delete object
3. Encapsulation
It refers to restricting access to certain details of an object and exposing only the necessary parts. Encapsulation allows data (attributes) and methods (functions) to be bundled together into a single unit (class) while controlling access to them.
class BankAccount: def __init__(self, account_number, balance): self.__account_number = account_number # Private attribute self.__balance = balance # Private attribute def deposit(self, amount): # Public method to deposit money if amount > 0: self.__balance += amount print(f"Deposited: ${amount}") else: print("Deposit amount must be positive.") def withdraw(self, amount): # Public method to withdraw money if 0 < amount <= self.__balance: self.__balance -= amount print(f"Withdrawn: ${amount}") else: print("Insufficient balance or invalid amount.") def get_balance(self): # Getter method to retrieve the balance return self.__balance def set_balance(self, new_balance): # Setter method to modify the balance (with validation) if new_balance >= 0: self.__balance = new_balance else: print("Balance cannot be negative.") account = BankAccount("1234567890", 500) # Create an object of the BankAccount class # Access private attributes using public methods account.deposit(200) # Deposited: $200 account.withdraw(100) # Withdrawn: $100 print(account.get_balance()) # 600 # Attempting to directly access private attributes (will fail) # print(account.__balance) # AttributeError
4. Inheritance
It allows a class (called the child class or subclass) to inherit attributes and methods from another class (called the parent class or base class). This promotes code reuse and establishes a hierarchical relationship between classes.
Type of inheritance :
- Single Inheritance: A child class inherits from one parent class.
- Multiple Inheritance: A child class inherits from multiple parent classes.
- Multilevel Inheritance: A child class inherits from a parent class, which itself inherits from another parent class.
- Hierarchical Inheritance: Multiple child classes inherit from the same parent class.
- Hybrid Inheritance: A combination of two or more types of inheritance.
##### Single Inheritance Example ##### class Animal: def __init__(self, name): self.name = name def speak(self): print(f"{self.name} makes a sound.") class Dog(Animal): def speak(self): print(f"{self.name} barks.") dog = Dog("Buddy") # Create an object of the child class dog.speak() # Output: Buddy barks ##### Multiple Inheritance Example ##### class Flyable: def fly(self): print("Can fly.") class Swimable: def swim(self): print("Can swim.") class Duck(Flyable, Swimable): def quack(self): print("Quacks.") # Create an object of the Duck class duck = Duck() duck.fly() # Output: Can fly. duck.swim() # Output: Can swim. duck.quack() # Output: Quacks. ##### Multilevel Inheritance Example ##### class Vehicle: def move(self): print("Vehicle is moving.") class Car(Vehicle): def drive(self): print("Car is driving.") class SportsCar(Car): def accelerate(self): print("Sports car accelerates quickly.") # Create an object of the SportsCar class sports_car = SportsCar() sports_car.move() # Output: Vehicle is moving. sports_car.drive() # Output: Car is driving. sports_car.accelerate() # Output: Sports car accelerates quickly. ##### Hierarchical Inheritance Example ##### # Base class class Parent: def func1(self): print("This function is in parent class.") # Derived class1 class Child1(Parent): def func2(self): print("This function is in child 1.") # Derivied class2 class Child2(Parent): def func3(self): print("This function is in child 2.") # Driver's code object1 = Child1() object2 = Child2() object1.func1() #This function is in parent class. object1.func2() #This function is in child 1. object2.func1() #This function is in parent class. object2.func3() #This function is in child 2. ##### Hybrid Inheritance Example ##### class School: def func1(self): print("This function is in school.") class Student1(School): def func2(self): print("This function is in student 1. ") class Student2(School): def func3(self): print("This function is in student 2.") class Student3(Student1, School): def func4(self): print("This function is in student 3.") # Driver's code object = Student3() object.func1() #This function is in school. object.func2() #This function is in student 1.
5. Polymorphism
It allows objects of different classes to be treated as objects of a common parent class. It enables a single interface to handle different types of objects, fostering flexibility and reusability in code.
Type of polymorphism :
- Compile-Time Polymorphism: Achieved through method overloading (not natively supported in Python but can be mimicked).
- Run-Time Polymorphism: Achieved through method overriding, where a child class provides a specific implementation of a method defined in the parent class.
##### Method overriding Example ##### class Shape: def area(self): return 0 class Rectangle(Shape): def __init__(self, width, height): self.width = width self.height = height def area(self): return self.width * self.height class Circle(Shape): def __init__(self, radius): self.radius = radius def area(self): return 3.14 * self.radius ** 2 shapes = [Rectangle(4, 5), Circle(3)] for shape in shapes: print(f"Area: {shape.area()}") # Output: Area: 20 Area: 28.26 ##### Method overloading Example ##### class Point: def __init__(self, x, y): self.x = x self.y = y def __add__(self, other): return Point(self.x + other.x, self.y + other.y) def __str__(self): return f"({self.x}, {self.y})" point1 = Point(1, 2) point2 = Point(3, 4) result = point1 + point2 print(result) # Output: (4, 6)
6. Abstraction
Data abstraction is one of the most essential concepts of Python OOPs which is used to hide irrelevant details from the user and show the details that are relevant to the users. Using abstract base classes (from the abc
module) we can implement abstraction.
from abc import ABC, abstractmethod class Shape(ABC): @abstractmethod def area(self): pass class Circle(Shape): def __init__(self, radius): self.radius = radius def area(self): return 3.14 * self.radius * self.radius circle = Circle(5) print(circle.area()) # Output: 78.5