Object Oriented Programming in Python is a programming paradigm that focuses on the concept of objects, which represent real-world entities, and their interactions. Python supports OOP and provides several features to define and work with classes and objects. Here are some key concepts in Python OOP:
- Classes and Objects: A class is a blueprint or template for creating objects, while an object is an instance of a class. The class defines the attributes (variables) and behaviors (methods) that the objects of that class will have.
class Person: def __init__(self, name, age): self.name = name self.age = age def greet(self): print(f"Hello, my name is {self.name} and I am {self.age} years old.") # Creating objects/instances of the Person class person1 = Person("John", 25) person2 = Person("Jane", 30) person1.greet() # Output: Hello, my name is John and I am 25 years old. person2.greet() # Output: Hello, my name is Jane and I am 30 years old.
- Encapsulation: Encapsulation refers to the bundling of data and methods within a class, where the internal state of the object is hidden from the outside. This allows for data protection and better organization of code.
class BankAccount: def __init__(self, account_number, balance): self.account_number = account_number self.__balance = balance # Encapsulated attribute def deposit(self, amount): self.__balance += amount def withdraw(self, amount): if amount <= self.__balance: self.__balance -= amount else: print("Insufficient balance") def get_balance(self): return self.__balance # Create a bank account object and interact with it using methods account = BankAccount("1234567890", 1000) print(account.get_balance()) # Output: 1000 account.deposit(500) print(account.get_balance()) # Output: 1500 account.withdraw(2000) # Output: Insufficient balance print(account.get_balance()) # Output: 1500
In this example, the BankAccount
class encapsulates the balance
attribute by making it private with the use of double underscores (__balance
). This encapsulation restricts direct access to the attribute from outside the class. Instead, the class provides methods (deposit()
, withdraw()
, and get_balance()
) to interact with and modify the encapsulated attribute. This ensures data protection and allows the class to control how the attribute is accessed and manipulated.
- Inheritance: Inheritance is a mechanism that allows a class (child class) to inherit properties and methods from another class (parent class). The child class can further extend or modify the inherited behavior.
class Student(Person): def __init__(self, name, age, roll_number): super().__init__(name, age) self.roll_number = roll_number def study(self): print(f"{self.name} is studying.") student = Student("Alice", 20, "123") student.greet() # Output: Hello, my name is Alice and I am 20 years old. student.study() # Output: Alice is studying.
Below, is a real-world example for better understand.
class Vehicle: def __init__(self, brand): self.brand = brand def drive(self): print(f"Driving the {self.brand}") class Car(Vehicle): def __init__(self, brand, model): super().__init__(brand) self.model = model def drive(self): print(f"Driving the {self.brand} {self.model}") class Bike(Vehicle): def __init__(self, brand, type): super().__init__(brand) self.type = type car = Car("Toyota", "Camry") bike = Bike("Honda", "Sport") car.drive() # Output: Driving the Toyota Camry bike.drive() # Output: Driving the Honda Sport
In this example, we have a base class Vehicle
with a drive()
method that prints a generic driving message. The Car
and Bike
classes are derived from the Vehicle
class using inheritance. They override the drive()
method with their own implementations. The Car
class adds the model
attribute and provides a more specific driving message, while the Bike
class adds the type
attribute. When we call the drive()
method on objects of Car
and Bike
, they exhibit the behavior specific to their class, but also inherit and utilize the behavior of the Vehicle
class.
- Polymorphism: Polymorphism allows objects of different classes to be treated as objects of a common base class. This enables code to work with different objects in a uniform way, based on their shared interface.
def introduce(person): person.greet() person = Person("Mike", 35) student = Student("Emily", 22, "456") introduce(person) # Output: Hello, my name is Mike and I am 35 years old. introduce(student) # Output: Hello, my name is Emily and I am 22 years old.
Below, is a real-world example for better understand.
class Dog: def speak(self): print("Woof!") class Cat: def speak(self): print("Meow!") class Cow: def speak(self): print("Moo!") def make_speak(animal): animal.speak() dog = Dog() cat = Cat() cow = Cow() make_speak(dog) # Output: Woof! make_speak(cat) # Output: Meow! make_speak(cow) # Output: Moo!
In this example, we define three classes: Dog
, Cat
, and Cow
. Each class has a speak()
method that prints a sound specific to that animal. The make_speak()
function takes an animal
object as a parameter and calls its speak()
method. We can pass different animal objects to the function, and it will call the appropriate speak()
method based on the object’s type. This demonstrates polymorphism, where different objects can be treated as objects of a common base class (animal
in this case) and exhibit different behaviors based on their specific implementation.
- Abstraction: Abstraction involves hiding unnecessary details and exposing only essential features to the users. It allows you to work with objects at a higher level without worrying about their internal implementation.
from abc import ABC, abstractmethod class Shape(ABC): @abstractmethod def calculate_area(self): pass class Rectangle(Shape): def __init__(self, width, height): self.width = width self.height = height def calculate_area(self): return self.width * self.height class Circle(Shape): def __init__(self, radius): self.radius = radius def calculate_area(self): return 3.14 * self.radius * self.radius # Create objects and work with them at a higher level of abstraction shapes = [Rectangle(4, 5), Circle(3)] for shape in shapes: area = shape.calculate_area() print(f"Area: {area}")
In this example, the Shape
class is an abstract base class (ABC) that defines a method calculate_area()
. This method is marked as abstractmethod
, indicating that it must be overridden in the concrete derived classes. The Rectangle
and Circle
classes inherit from Shape
and provide their own implementation of calculate_area()
. We can work with different shapes using a list of Shape
objects and call the calculate_area()
method without knowing the internal details of each shape.
Conclusion:
These are just a few key concepts of OOP in Python. By utilizing these concepts, you can create well-structured, reusable, and maintainable code that models real-world entities and their interactions.