Your Go-to Guide to Master Python Part-2: Advanced Concepts and Object-Oriented Programming

Your Go-to Guide to Master Python Part-2: Advanced Concepts and Object-Oriented Programming

·

6 min read

In the previous part of our comprehensive Python guide, we covered the fundamentals of Python, including variables, data types, operators, control flow statements, looping statements, and data structures. If you haven't checked out the previous part, click here: https://hashnode.com/post/clkh8o5k5000109l0hn0chhke

Now, let's dive deeper into a bit more advanced concepts, object-oriented programming (OOP), and file handling in Python.

Methods in Python

In Python, methods are functions that belong to a class and operate on objects of that class. There are three types of methods.

Instance Methods

Instance methods take "self" as the first parameter and can access and modify the object's attributes.

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def greet(self):
        return f"Hello, my name is {self.name} and I am {self.age} years old."


# Creating an instance of the class
person1 = Person("J.Robert Oppenheimer", 41)

# Calling the instance method
print(person1.greet())

Output:

Hello, my name is J.Robert Oppenheimer and I am 41 years old.

Class Methods

Class methods take "cls" (the class itself) as the first parameter and can modify class-level attributes.

class Dog:
    count = 0  # Class-level attribute

    def __init__(self, name):
        self.name = name
        Dog.count += 1

    @classmethod
    def get_total_dogs(cls):
        return cls.count


# Creating instances of the class
dog1 = Dog("Buddy")
dog2 = Dog("Max")

# Calling the class method
print("Total dogs:", Dog.get_total_dogs())

Output:

Total dogs: 2

Static Methods

Static methods do not take any special parameters (such as "self" or "cls") and are not related to the class or instance.

class MathUtils:
    @staticmethod
    def add(x, y):
        return x + y

    @staticmethod
    def multiply(x, y):
        return x * y


# Calling static methods directly without creating an instance of the class
print("Sum:", MathUtils.add(5, 3))
print("Product:", MathUtils.multiply(5, 3))

Output:

Sum: 8
Product: 15

Object-Oriented Programming (OOP) Concepts in Python

Object-Oriented Programming is a paradigm that uses objects and classes to model real-world entities.

Class and Object

A class is a blueprint for creating objects, and objects are instances of those classes.

class Car:
    def __init__(self, make, model):
        self.make = make
        self.model = model

    def display_info(self):
        return f"{self.make} {self.model}"


# Creating instances of the class (objects)
car1 = Car("Bugyatti", "Veyron")
car2 = Car("Mercedes-Benz", "G-Wagon")

# Calling the instance method
print("Car 1:", car1.display_info())
print("Car 2:", car2.display_info())

Output:

Car 1: Bugyatti Veyron
Car 2: Mercedes-Benz G-Wagon

Polymorphism

Polymorphism allows objects of different classes to be treated as objects of a common superclass, providing a consistent interface for various types of objects. This concept allows a single method or function to handle different data types or classes. Types:

1. Compile-Time Polymorphism (Static Polymorphism):

Compile-time polymorphism is achieved through method overloading and operator overloading. In method overloading, multiple methods with the same name but different parameters are defined in the same class.

class MathOperations:
    def add(self, a, b):
        return a + b

    def add(self, a, b, c):
        return a + b + c


math_op = MathOperations()
print("Sum of two numbers:", math_op.add(5, 3))
print("Sum of three numbers:", math_op.add(5, 3, 2))

Output:

Sum of three numbers: 10
Sum of three numbers: 10

2. Run-Time Polymorphism (Dynamic Polymorphism):

Run-time polymorphism is achieved through method overriding, where a subclass provides a specific implementation for a method that is already defined in its superclass.

class Animal:
    def make_sound(self):
        return "Generic animal sound"


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)
animal_sounds(cat)

Output:

Woof!
Meow!

Data Abstraction

Data abstraction is a concept of displaying only essential information and hiding the implementation details. It allows us to focus on what an object does rather than how it does it. Abstraction is achieved through abstract classes and interfaces.

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


class Square(Shape):
    def __init__(self, side):
        self.side = side

    def area(self):
        return self.side * self.side


# You cannot create an instance of an abstract class directly
# shape = Shape()  # This will raise an error

circle = Circle(5)
square = Square(4)

print("Area of the circle:", circle.area())
print("Area of the square:", square.area())

Output:

Area of the circle: 78.5
Area of the square: 16

Inheritance

Inheritance allows a class (subclass) to inherit attributes and methods from another class (superclass).

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

    def make_sound(self):
        pass


class Dog(Animal):
    def __init__(self, breed):
        super().__init__("Dog")
        self.breed = breed

    def make_sound(self):
        return "Woof!"


# Creating an instance of the subclass
dog = Dog("Golden Retriever")

# Calling the overridden method from the superclass
print("Species:", dog.species)

# Calling the method from the subclass
print("Breed:", dog.breed)
print("Sound:", dog.make_sound()

Output:

Species: Dog
Breed: Golden Retriever
Sound: Woof!

Encapsulation

Encapsulation is the concept of hiding data within a class and providing methods to access or modify that data.

class BankAccount:
    def __init__(self):
        self.__balance = 0  # Private 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


# Creating an instance of the class
account = BankAccount()

# Accessing and modifying the private attribute using public methods
account.deposit(1000)
account.withdraw(500)
print("Balance:", account.get_balance())

Output:

Balance: 500

File Handling in Python

File handling allows reading from and writing to external files.

Reading from a File

The "open" function is used to open a file, and the "read" method is used to read its contents.

with open("data.txt", "r") as file:
    content = file.read()

print(content)

Writing to a File

The "open" function is used to open a file with the "write" mode, and the "write" method is used to write data.

with open("output.txt", "w") as file:
    file.write("Hello, Python!")

Real-World Use Cases

Methods

Methods allow us to encapsulate functionality within classes, making code more organized and reusable. They are extensively used in building applications, web development, and data analysis.

Object-Oriented Programming (OOP)

OOP enables developers to create complex systems with easily maintainable and scalable code. It is widely used in software development, game development, and modeling real-world entities.

File Handling

File handling is essential in applications that need to read or write data to files, such as data analysis, logging, and data storage.

Conclusion

In this part of our Python guide, we explored different types of methods, object-oriented programming concepts, and file handling in detail. These concepts are crucial in building sophisticated and efficient Python applications across various domains. As you continue your Python journey, make sure to practice and apply these concepts to real-world scenarios to become a true Python expert. In the next part, we'll explore more about different domains where Python is being used extensively and push our horizons even further. Until then, Happy Learning!

Did you find this article valuable?

Support Sanjay's blog by becoming a sponsor. Any amount is appreciated!