Python OOPS

Python OOPs Tutorial

Introduction

Object-Oriented Programming (OOP) is a programming paradigm that organizes code into objects, allowing developers to model real-world entities and their interactions. Python is an object-oriented language that supports these principles, making it easy to write modular, maintainable, and scalable code.

Terms in OOPS

  • Class: A class is a blueprint or template that defines the structure and behavior of objects. It encapsulates data attributes and methods (functions) that operate on the data.
  • Object: An object is an instance of a class. It represents a specific instance of the class, with its own set of data and behavior.
  • Attributes: Attributes are variables that store data within a class or object.
  • Methods: Methods are functions defined within a class that performs actions or operations on the data stored in the class or object.

Here’s a simple example that demonstrates the concepts of classes, objects, attributes, and methods in Python:

				
					class Car:
    def __init__(self, make, model, year):
        self.make = make          # Attribute: make of the car
        self.model = model        # Attribute: model of the car
        self.year = year          # Attribute: manufacturing year of the car
        self.is_running = False   # Attribute: whether the car is running or not
	
    def start(self):
        self.is_running = True
        print(f"The {self.year} {self.make} {self.model} is now running.")

    def stop(self):
        self.is_running = False
        print(f"The {self.year} {self.make} {self.model} has been stopped.")

    def honk(self):
        if self.is_running:
            print("Honk! Honk!")
        else:
            print("The car needs to be running to honk.")

# Creating objects (instances) of the Car class
car1 = Car("Toyota", "Camry", 2022)
car2 = Car("Ford", "Mustang", 2023)

# Using methods and accessing attributes
car1.start()          # Output: "The 2022 Toyota Camry is now running."
car2.start()          # Output: "The 2023 Ford Mustang is now running."

car1.honk()           # Output: "Honk! Honk!"
car2.honk()           # Output: "Honk! Honk!"

car1.stop()           # Output: "The 2022 Toyota Camry has been stopped."
car2.stop()           # Output: "The 2023 Ford Mustang has been stopped."

				
			

In this example, we have a Car class with attributes like make, model, year, and is_running. It also has methods such as start, stop, and honk that interact with these attributes. We create two instances of the Car class (car1 and car2) and use methods to perform actions on them. This demonstrates how classes define the structure and behavior of objects, and how objects interact with methods and attributes.

Python OOPs Concepts

Polymorphism

Polymorphism allows objects of different classes to be treated as objects of a common superclass. It enables the same method name to behave differently based on the context.

				
					class Animal:
    def make_sound(self):
        pass

class Dog(Animal):
    def make_sound(self):
        return "Woof!"

class Cat(Animal):
    def make_sound(self):
        return "Meow!"

def animal_sounds(animal):
    print(animal.make_sound())

dog = Dog()
cat = Cat()

animal_sounds(dog)  # Output: "Woof!"
animal_sounds(cat)  # Output: "Meow!"

				
			

Encapsulation

Encapsulation refers to the concept of bundling data and methods that operate on that data into a single unit, i.e., a class. It prevents direct access to data from outside the class and promotes data hiding.

				
					class Student:
    def __init__(self, name, age):
        self.name = name
        self.__age = age  # Private attribute

    def get_age(self):
        return self.__age

    def set_age(self, age):
        if age > 0:
            self.__age = age

student = Student("Alice", 20)
print(student.get_age())  # Output: 20
student.set_age(21)
print(student.get_age())  # Output: 21

				
			

Inheritance

Inheritance allows a new class (subclass/derived class) to inherit attributes and methods from an existing class (superclass/base class). It promotes code reusability and the creation of specialized classes.

				
					class Vehicle:
    def __init__(self, brand):
        self.brand = brand

    def drive(self):
        pass

class Car(Vehicle):
    def drive(self):
        return f"Driving the {self.brand} car"

class Bike(Vehicle):
    def drive(self):
        return f"Riding the {self.brand} bike"

car = Car("Toyota")
bike = Bike("Honda")

print(car.drive())  # Output: "Driving the Toyota car"
print(bike.drive())  # Output: "Riding the Honda bike"

				
			

Types of Inheritance

  1. Single Inheritance: Single inheritance involves one subclass inheriting from a single superclass.
  2. Multiple Inheritance: Multiple inheritance involves a subclass inheriting from multiple superclasses.
  3. Multilevel Inheritance: Multilevel inheritance involves a chain of inheritance with a subclass inheriting from another subclass.

Here’s an example that demonstrates different types of inheritance in Python: single inheritance, multiple inheritance, and multilevel inheritance.

				
					# Single Inheritance
class Animal:
    def __init__(self, species):
        self.species = species

    def speak(self):
        pass

class Dog(Animal):
    def speak(self):
        return "Woof!"

class Cat(Animal):
    def speak(self):
        return "Meow!"

dog = Dog("Canine")
cat = Cat("Feline")

print(dog.species)  # Output: "Canine"
print(dog.speak())  # Output: "Woof!"

print(cat.species)  # Output: "Feline"
print(cat.speak())  # Output: "Meow!"
				
			
				
					# Multiple Inheritance
class Swimmer:
    def swim(self):
        return "Swimming"

class Flyer:
    def fly(self):
        return "Flying"

class Duck(Swimmer, Flyer):
    def speak(self):
        return "Quack!"

duck = Duck()

print(duck.swim())  # Output: "Swimming"
print(duck.fly())   # Output: "Flying"
print(duck.speak()) # Output: "Quack"
				
			
				
					# Multilevel Inheritance
class Vehicle:
    def start(self):
        return "Starting vehicle"

class Car(Vehicle):
    def drive(self):
        return "Driving car"

class ElectricCar(Car):
    def charge(self):
        return "Charging electric car"

electric_car = ElectricCar()

print(electric_car.start())  # Output: "Starting vehicle"
print(electric_car.drive())  # Output: "Driving car"
print(electric_car.charge()) # Output: "Charging electric car"
				
			

Python OOPs Class Methods

  1. Class Method

In Python, a class method is a type of method that is bound to the class itself rather than to instances of the class. It can access and modify class-level attributes and perform actions related to the class as a whole. Class methods are defined using the @classmethod decorator and take the class itself as the first parameter, conventionally named cls. This makes them different from instance methods, which take the instance itself (self) as the first parameter.

Key characteristics and usage of class methods

  1. Definition: Class methods are methods defined within a class, just like instance methods, but they are decorated with @classmethod.
  2. Parameters: A class method takes the class itself as the first parameter, conventionally named cls. This allows you to access and modify class-level attributes.
  3. Access to Class Attributes: Class methods have access to class-level attributes and can modify them. They can also access other class methods.
  4. Usage: Class methods are often used for methods that perform actions related to the class itself, rather than specific instances. They are called on the class, not on instances.
  5. Decorator: The @classmethod decorator is used to define a class method. It indicates that the method is intended to be a class method.
  6. Invocation: Class methods are called using the class name (ClassName.method_name()), not on instances of the class.
  7. Instance-independent: Unlike instance methods, class methods don’t depend on the attributes or state of individual instances. They operate on the class itself.
  8. Common Uses:
  • Creating factory methods to construct instances with specific properties.
  • Providing alternative constructors for class instances.
  • Modifying and accessing class-level attributes.
  • Performing actions related to the class as a whole.
  1. Utility Methods: Class methods are often used to create utility functions that are logically related to the class but don’t need access to instance-specific data.
  2. Static Methods vs. Class Methods: Class methods receive the class itself (cls) as a parameter, allowing them to access and modify class-level attributes. Static methods don’t have access to class attributes and are more suited for utility functions.
				
					class MyClass:
    class_variable = "I am a class variable"
	
    def __init__(self, instance_variable):
        self.instance_variable = instance_variable

    @classmethod
    def from_class_variable(cls):
        return cls(cls.class_variable)

    @classmethod
    def modify_class_variable(cls, new_value):
        cls.class_variable = new_value

obj1 = MyClass("Instance 1")
obj2 = MyClass("Instance 2")

print(obj1.instance_variable)  # Output: "Instance 1"
print(obj2.instance_variable)  # Output: "Instance 2"

# Using the class method to create an instance
obj3 = MyClass.from_class_variable()
print(obj3.instance_variable)  # Output: "I am a class variable"

# Modifying the class variable using the class method
MyClass.modify_class_variable("New class variable value")
print(obj1.class_variable)     # Output: "New class variable value"
print(obj2.class_variable)     # Output: "New class variable value"

				
			
  1. Static Method

A static method is a method that is defined within a class but is not bound to the class instance or class-level attributes. It doesn’t receive any implicit reference to the class or its instances as parameters. Static methods are defined using the @staticmethod decorator. Static methods are often used to create utility functions that are logically related to the class but don’t require access to instance-specific or class-level data.

Key characteristics and usage of Static methods

  1. Definition: Static methods are methods defined within a class, just like instance methods, but they are decorated with @staticmethod.
  2. No Implicit Parameters: Static methods do not receive any implicit reference to the class or its instances as parameters. They behave like regular functions, except they are defined within a class.
  3. No Access to Instance or Class Attributes: Static methods cannot access or modify instance-specific data or class-level attributes. They are isolated from the rest of the class’s context.
  4. Usage: Static methods are used for utility functions that are logically related to the class but do not require access to instance-specific or class-level data.
  5. Decorator: The @staticmethod decorator is used to define a static method. It indicates that the method is intended to be a static method.
  6. Invocation: Static methods are called using the class name (ClassName.method_name()), similar to class methods. However, static methods do not receive any implicit cls parameter.
  7. Instance-Independent: Like class methods, static methods are also independent of the attributes or state of individual instances. They operate in a self-contained manner.
  8. Common Uses:
  • Creating utility functions that are related to the class but do not require class-level or instance-level data.
  • Implementing functions that are logically associated with the class but do not need access to instance or class context.
  1. Alternative to Global Functions: Static methods provide a way to keep utility functions close to the relevant class, avoiding global scope clutter.
  2. Static Methods vs. Class Methods: Class methods receive the class itself (cls) as a parameter and can access and modify class-level attributes. Static methods do not have access to class attributes and are often used for isolated utility functions.
				
					class MathUtils:
    @staticmethod
    def add(x, y):
        return x + y
    
    @staticmethod
    def multiply(x, y):
        return x * y

result_add = MathUtils.add(5, 3)
result_multiply = MathUtils.multiply(4, 6)

print(result_add)       # Output: 8
print(result_multiply)  # Output: 24

				
			

Leave a Comment