Showing posts with label Python. Show all posts
Showing posts with label Python. Show all posts

Wednesday, 19 March 2025

Pandas

5.1 Pandas

Pandas is one of the most powerful and widely used libraries in Python for data manipulation and analysis. It provides easy-to-use data structures and functions to efficiently handle large datasets.

Why Use Pandas?

  • Efficient data handling with DataFrames and Series
  • Supports CSV, Excel, SQL, JSON, and many other file formats
  • Powerful data cleaning, manipulation, and transformation tools
  • Built-in statistical and analytical functions
  • Easy integration with NumPy, Matplotlib, and other libraries

Installing Pandas

If you don’t have Pandas installed, you can install it using:


pip install pandas

1. Importing Pandas


import pandas as pd

2. Creating DataFrames

A DataFrame is a table-like structure that consists of rows and columns.

a) Creating a DataFrame from a Dictionary


data = { 'Name': ['Alice', 'Bob', 'Charlie'], 'Age': [25, 30, 35], 'City': ['New York', 'Los Angeles', 'Chicago'] } df = pd.DataFrame(data) print(df)

Output:


Name Age City 0 Alice 25 New York 1 Bob 30 Los Angeles 2 Charlie 35 Chicago

b) Creating a DataFrame from a CSV File


df = pd.read_csv('data.csv') print(df.head()) # Display first 5 rows

3. Basic DataFrame Operations

a) Checking Data Information


print(df.info()) # Summary of the dataset print(df.describe()) # Statistical summary print(df.shape) # Rows and columns count

b) Selecting Columns


print(df['Name']) # Selecting a single column print(df[['Name', 'Age']]) # Selecting multiple columns

c) Selecting Rows


print(df.iloc[0]) # Selecting the first row print(df.loc[df['Age'] > 30]) # Filtering rows where Age > 30

4. Data Manipulation

a) Adding a New Column


df['Salary'] = [50000, 60000, 70000] print(df)

b) Updating Values


df.loc[df['Name'] == 'Alice', 'Age'] = 26

c) Dropping a Column


df.drop(columns=['Salary'], inplace=True)

d) Handling Missing Data


df.fillna(0, inplace=True) # Replace NaN values with 0 df.dropna(inplace=True) # Remove rows with NaN values

5. Grouping and Aggregation


df_grouped = df.groupby('City')['Age'].mean() print(df_grouped)

6. Merging and Joining DataFrames


df1 = pd.DataFrame({'ID': [1, 2], 'Name': ['Alice', 'Bob']}) df2 = pd.DataFrame({'ID': [1, 2], 'Salary': [50000, 60000]}) df_merged = pd.merge(df1, df2, on='ID') print(df_merged)

7. Exporting Data


df.to_csv('output.csv', index=False) # Save as CSV df.to_excel('output.xlsx', index=False) # Save as Excel

Conclusion

Pandas is an essential tool for data analysis and manipulation in Python. It simplifies handling and processing of structured data, making it a must-learn library for data science and machine learning.

Introduction to Built in Package in Python

 Python provides a vast collection of built-in packages (also known as standard libraries) that simplify coding and enhance functionality. These built-in packages help developers perform tasks without needing external dependencies, making Python a powerful and versatile programming language.

What Are Built-in Packages?

Built-in packages are pre-installed modules in Python that provide various functionalities, such as file handling, mathematical operations, system interactions, and web handling. You can import and use these modules without installing them separately.

Commonly Used Built-in Packages

Here are some of the most commonly used built-in packages in Python:

1. math - Mathematical Operations

The math module provides mathematical functions like square root, trigonometric functions, logarithms, and more.

import math

 

print(math.sqrt(25))  # Output: 5.0

print(math.pi)        # Output: 3.141592653589793

print(math.factorial(5))  # Output: 120

2. random - Generating Random Numbers

The random module is used for generating random numbers, selecting random elements, and shuffling sequences.

import random

 

print(random.randint(1, 10))  # Random number between 1 and 10

print(random.choice(["apple", "banana", "cherry"]))  # Random selection from a list

3. datetime - Working with Dates and Time

The datetime module provides functions to handle dates and time-related tasks.

import datetime

 

current_time = datetime.datetime.now()

print("Current Time:", current_time)

4. os - Interacting with the Operating System

The os module provides functionalities to interact with the operating system, such as file handling and directory management.

import os

 

print(os.getcwd())  # Get the current working directory

os.mkdir("new_folder")  # Create a new directory

5. sys - System-specific Functions

The sys module provides access to system-specific parameters and functions.

import sys

 

print(sys.version)  # Prints Python version

print(sys.platform)  # Prints the operating system platform

6. json - Handling JSON Data

The json module helps in encoding and decoding JSON data.

import json

 

data = {"name": "John", "age": 25}

json_data = json.dumps(data)

print(json_data)  # Convert dictionary to JSON string

7. re - Regular Expressions

The re module is used for pattern matching and working with regular expressions.

import re

text = "Hello, my number is 123-456-7890"

pattern = r"\d{3}-\d{3}-\d{4}"

match = re.search(pattern, text)

if match:

    print("Phone number found:", match.group())

8. collections - Advanced Data Structures

The collections module provides specialized container data types like Counter, defaultdict, and deque.

from collections import Counter

 

words = ["apple", "banana", "apple", "orange", "banana", "apple"]

word_count = Counter(words)

print(word_count)  # Output: Counter({'apple': 3, 'banana': 2, 'orange': 1})

Conclusion

Python's built-in packages make programming easier by providing ready-to-use functionalities. By mastering these modules, you can simplify your code and focus more on problem-solving rather than implementing low-level functionalities.

 

Thursday, 6 March 2025

Polymorphism in Python

Polymorphism in Python

Polymorphism is a fundamental concept in Object-Oriented Programming (OOP) that allows objects of different classes to be treated uniformly. It enables a single interface to represent different underlying forms (data types), enhancing code flexibility and reusability.


Why Use Polymorphism?

  1. Code Reusability: Allows methods to work with different types of objects.
  2. Simplified Code: Reduces the need for complex if-else or type-checking statements.
  3. Flexibility: Supports dynamic behavior in programming.
  4. Extensibility: Allows adding new classes with minimal changes to existing code.

Types of Polymorphism in Python

  1. Compile-Time Polymorphism (Method Overloading)
  2. Run-Time Polymorphism (Method Overriding)
  3. Polymorphism with Functions and Objects
  4. Polymorphism with Class Methods
  5. Polymorphism with Inheritance

1. Compile-Time Polymorphism (Method Overloading)

Python does not directly support method overloading like other languages (e.g., Java). However, you can achieve similar behavior using default parameters or *args and **kwargs.


class MathOperations: # Single method handling multiple types of parameters def add(self, a=None, b=None, c=None): if a is not None and b is not None and c is not None: return a + b + c elif a is not None and b is not None: return a + b else: return a math = MathOperations() print(math.add(5, 10)) # Output: 15 print(math.add(5, 10, 15)) # Output: 30

Key Points:

  • Python does not support true method overloading, but you can use default arguments.
  • This approach mimics method overloading by providing flexibility in parameter handling.

2. Run-Time Polymorphism (Method Overriding)

When a child class provides a specific implementation of a method that is already defined in its parent class.


class Animal: def sound(self): print("Animal makes a sound") class Dog(Animal): def sound(self): print("Dog barks") class Cat(Animal): def sound(self): print("Cat meows") # Demonstrating polymorphism animals = [Animal(), Dog(), Cat()] for animal in animals: animal.sound()

Output:


Animal makes a sound Dog barks Cat meows

Key Points:

  • Method overriding enables dynamic polymorphism.
  • The method to call is determined at runtime based on the object type.

3. Polymorphism with Functions and Objects

Built-in functions like len() demonstrate polymorphism by working with different data types.


print(len("Hello")) # Output: 5 (string) print(len([1, 2, 3])) # Output: 3 (list) print(len((10, 20))) # Output: 2 (tuple)

Key Points:

  • The len() function works with multiple data types.
  • The behavior of len() is consistent but adapts to the data type.

4. Polymorphism with Class Methods

You can create polymorphic behavior by defining methods with the same name in different classes.


class Rectangle: def area(self, length, width): return length * width class Circle: def area(self, radius): return 3.14 * radius * radius # Polymorphism with class methods shapes = [Rectangle(), Circle()] for shape in shapes: if isinstance(shape, Rectangle): print("Area of Rectangle:", shape.area(5, 3)) # Output: 15 elif isinstance(shape, Circle): print("Area of Circle:", shape.area(4)) # Output: 50.24

Key Points:

  • The same method name (area) is used in different classes.
  • The specific method called depends on the object type.

5. Polymorphism with Inheritance


class Bird: def fly(self): print("Bird can fly") class Sparrow(Bird): def fly(self): print("Sparrow flies fast") class Ostrich(Bird): def fly(self): print("Ostrich can't fly") # Demonstrating polymorphism with inheritance for bird in [Bird(), Sparrow(), Ostrich()]: bird.fly()

Output:


Bird can fly Sparrow flies fast Ostrich can't fly

Key Points:

  • The fly() method is overridden in subclasses.
  • Polymorphism allows the appropriate method to be called at runtime.

Polymorphism with Abstract Classes

Abstract classes use polymorphism by defining abstract methods that are implemented differently in subclasses.


from abc import ABC, abstractmethod class Animal(ABC): @abstractmethod def make_sound(self): pass class Dog(Animal): def make_sound(self): print("Dog barks") class Cat(Animal): def make_sound(self): print("Cat meows") # Polymorphism with abstract class for animal in [Dog(), Cat()]: animal.make_sound()

Output:


Dog barks Cat meows

Key Points:

  • Abstract classes enforce method implementation in derived classes.
  • Supports polymorphic behavior through abstract methods.

Polymorphism with Operator Overloading

You can override special methods to change the behavior of operators for user-defined objects.


class Point: def __init__(self, x, y): self.x = x self.y = y # Overloading the + operator 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) # Using + on Point objects result = point1 + point2 print(result) # Output: (4, 6)

Key Points:

  • Operator overloading uses special methods like __add__, __str__, etc.
  • Enables polymorphic behavior with built-in operators.

Best Practices for Polymorphism

  1. Use Method Overriding: Promote dynamic polymorphism with method overriding.
  2. Leverage Abstract Classes: Use abstract base classes (ABC) to enforce polymorphism.
  3. Avoid Excessive Type Checks: Minimize isinstance() and type() checks.
  4. Design for Extensibility: Create methods that work with multiple object types.
  5. Keep Code Readable: Avoid complex polymorphic structures that reduce code clarity.

When to Use Polymorphism:

  • When different classes share a common interface.
  • When the exact class type is not important.
  • When you want to define methods that can operate on any object.

Conclusion:

Polymorphism enhances flexibility and maintainability in Python programming. By allowing different objects to respond to the same method call, polymorphism supports cleaner code and reduces dependencies.

Inheritance in Python

Inheritance is an object-oriented programming (OOP) concept that allows a class (child class) to inherit attributes and methods from another class (parent class). It promotes code reusability and establishes a relationship between classes.


Why Use Inheritance?

  1. Code Reusability: Avoids redundancy by reusing existing code.
  2. Maintainability: Centralizes common code in a base class.
  3. Extensibility: Enables modifying or extending functionality without altering existing code.
  4. Polymorphism Support: Allows for method overriding and dynamic method resolution.

Types of Inheritance in Python

  1. Single Inheritance
  2. Multiple Inheritance
  3. Multilevel Inheritance
  4. Hierarchical Inheritance
  5. Hybrid Inheritance

1. Single Inheritance

A child class inherits from a single parent class.


# Parent class class Animal: def speak(self): print("Animal makes a sound") # Child class class Dog(Animal): def bark(self): print("Dog barks") # Creating an object of Dog class dog = Dog() dog.speak() # Output: Animal makes a sound dog.bark() # Output: Dog barks

Key Points:

  • Simplest form of inheritance.
  • The child class has access to the parent class methods.

2. Multiple Inheritance

A child class inherits from more than one parent class.


# Parent class 1 class Father: def height(self): print("Height from Father") # Parent class 2 class Mother: def color(self): print("Color from Mother") # Child class class Child(Father, Mother): def display(self): print("Child's unique method") # Creating an object of Child class child = Child() child.height() # Output: Height from Father child.color() # Output: Color from Mother child.display() # Output: Child's unique method

Key Points:

  • Can inherit features from multiple classes.
  • Method Resolution Order (MRO) defines the method search order.

3. Multilevel Inheritance

A child class inherits from a parent class, which in turn inherits from another parent class.


# Grandparent class class Animal: def speak(self): print("Animal speaks") # Parent class class Dog(Animal): def bark(self): print("Dog barks") # Child class class Puppy(Dog): def weep(self): print("Puppy weeps") # Creating an object of Puppy class puppy = Puppy() puppy.speak() # Output: Animal speaks puppy.bark() # Output: Dog barks puppy.weep() # Output: Puppy weeps

Key Points:

  • Establishes a hierarchical relationship.
  • The child class has access to all ancestor methods.

4. Hierarchical Inheritance

Multiple child classes inherit from a single parent class.


# Parent class class Vehicle: def engine(self): print("Engine of Vehicle") # Child class 1 class Car(Vehicle): def wheels(self): print("Car has 4 wheels") # Child class 2 class Bike(Vehicle): def wheels(self): print("Bike has 2 wheels") # Creating objects of child classes car = Car() car.engine() # Output: Engine of Vehicle car.wheels() # Output: Car has 4 wheels bike = Bike() bike.engine() # Output: Engine of Vehicle bike.wheels() # Output: Bike has 2 wheels

Key Points:

  • Useful when multiple classes share common functionality.
  • Provides code reuse for common behavior.

5. Hybrid Inheritance

A combination of two or more types of inheritance.


class Animal: def speak(self): print("Animal speaks") class Mammal(Animal): def walk(self): print("Mammal walks") class Bird(Animal): def fly(self): print("Bird flies") class Bat(Mammal, Bird): def nocturnal(self): print("Bat is nocturnal") # Creating an object of Bat class bat = Bat() bat.speak() # Output: Animal speaks bat.walk() # Output: Mammal walks bat.fly() # Output: Bird flies bat.nocturnal() # Output: Bat is nocturnal

Key Points:

  • Can lead to complex structures.
  • Requires understanding of Method Resolution Order (MRO).

Method Overriding

A child class can override a method of the parent class.


class Animal: def sound(self): print("Animal makes a sound") class Dog(Animal): def sound(self): print("Dog barks") # Creating an object of Dog class dog = Dog() dog.sound() # Output: Dog barks

Key Points:

  • Enhances or modifies the parent class method.
  • Useful in polymorphism.

The super() Function

The super() function allows you to call methods of the parent class.


class Animal: def sound(self): print("Animal makes a sound") class Dog(Animal): def sound(self): super().sound() # Calls the parent class method print("Dog barks") # Creating an object of Dog class dog = Dog() dog.sound()

Output:

Animal makes a sound Dog barks

Key Points:

  • Useful in method overriding.
  • Avoids the need to hardcode the parent class name.

The isinstance() and issubclass() Functions

isinstance(object, class)

Checks if an object is an instance of a class (or a subclass).


class Animal: pass class Dog(Animal): pass dog = Dog() print(isinstance(dog, Dog)) # Output: True print(isinstance(dog, Animal)) # Output: True

issubclass(subclass, superclass)

Checks if a class is a subclass of another class.


print(issubclass(Dog, Animal)) # Output: True print(issubclass(Animal, Dog)) # Output: False

Best Practices for Inheritance

  1. Avoid deep inheritance chains: Prefer composition over inheritance when possible.
  2. Use super() to call parent class methods.
  3. Keep the inheritance hierarchy simple and readable.
  4. Apply method overriding only when necessary.
  5. Understand the Method Resolution Order (MRO), especially in multiple inheritance.

When to Use Inheritance:

  • When you need to model relationships like "is-a" (e.g., a Dog is an Animal).
  • To reuse code across similar classes.
  • When you need to extend functionality of existing classes.

Conclusion

Inheritance is a powerful tool in OOP that promotes code reuse, enhances maintainability, and simplifies complex systems. However, it is crucial to use inheritance wisely and avoid overcomplicating class hierarchies.

self Parameter in Python

The self Parameter in Python

The self parameter is a reference to the current instance of a class. It is used to access variables and methods that belong to the class.


Why self is Important:

  1. Access Instance Variables: Allows each object to have unique attributes.
  2. Call Instance Methods: Helps in calling methods from within the class.
  3. Maintain Object Context: Differentiates between instance variables and local variables.

How self Works:

When a method is called using an object, Python automatically passes the object as the first parameter to the method, which is self.

class Person: # Constructor with 'self' parameter def __init__(self, name, age): self.name = name # 'self.name' is an instance variable self.age = age # Method using 'self' to access attributes def greet(self): print(f"Hello, my name is {self.name} and I am {self.age} years old.") # Creating an object person = Person("Alice", 25) person.greet() # Output: Hello, my name is Alice and I am 25 years old.

Explanation:

  • self.name = name: self.name is an instance variable, while name is a local variable.
  • self helps distinguish between instance attributes and local parameters.

Modifying Object Properties with self

class Car: def __init__(self, brand, color): self.brand = brand self.color = color def update_color(self, new_color): self.color = new_color # Updating attribute using 'self' def display_info(self): print(f"Brand: {self.brand}, Color: {self.color}") # Creating an object car = Car("Tesla", "Red") car.display_info() # Output: Brand: Tesla, Color: Red # Modifying color using 'self' car.update_color("Blue") car.display_info() # Output: Brand: Tesla, Color: Blue

Key Points:

  • self is used to modify instance variables.
  • Helps in maintaining the object's state.

self with Multiple Objects

class Dog: def __init__(self, name, breed): self.name = name self.breed = breed def speak(self): print(f"{self.name} says: Woof!") # Creating multiple objects dog1 = Dog("Buddy", "Golden Retriever") dog2 = Dog("Max", "Bulldog") dog1.speak() # Output: Buddy says: Woof! dog2.speak() # Output: Max says: Woof!

Explanation:

  • Each object maintains its own data using self.
  • Methods can access data that is specific to the object.

Using self in Class Methods and Static Methods

Instance Method:

  • Takes self as the first parameter.
  • Can modify object state and access class attributes.

class Student: def __init__(self, name, grade): self.name = name self.grade = grade def display_info(self): # Instance method print(f"Name: {self.name}, Grade: {self.grade}") student = Student("John", "A") student.display_info() # Output: Name: John, Grade: A

Class Method (@classmethod):

  • Uses cls instead of self.
  • Can modify class state that applies to all instances.

class School: school_name = "ABC High School" @classmethod def change_school_name(cls, new_name): cls.school_name = new_name School.change_school_name("XYZ High School") print(School.school_name) # Output: XYZ High School

Static Method (@staticmethod):

  • Does not take self or cls as a parameter.
  • Cannot modify object or class state.

class Math: @staticmethod def add(a, b): return a + b print(Math.add(5, 3)) # Output: 8

Misconceptions about self

  1. Not a Keyword:
    • self is not a reserved keyword. You can use any name, but it is strongly recommended to use self for readability and convention.

class Example: def __init__(this, value): # 'this' instead of 'self' this.value = value def display(this): print(this.value) obj = Example(10) obj.display() # Output: 10
  1. Must be Explicitly Included:
    • Omitting self in the method definition will cause an error.

class Example: def method_without_self(): # Missing 'self' print("This will cause an error") obj = Example() # obj.method_without_self() # TypeError: method_without_self() takes 0 positional arguments but 1 was given

self in Inheritance

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): super().speak() # Calls the parent class method print(f"{self.name} barks") dog = Dog("Buddy") dog.speak()

Output:

Buddy makes a sound Buddy barks

Key Points:

  • self helps in calling parent class methods using super().
  • Maintains object-specific behavior in inherited classes.

When Not to Use self:

  • Inside Class Methods (@classmethod): Use cls instead of self.
  • Inside Static Methods (@staticmethod): Neither self nor cls is required.

Best Practices with self:

  1. Always use self as the first parameter in instance methods.
  2. Avoid renaming self to other variables unless absolutely necessary.
  3. Use self to access attributes and methods within the class.
  4. Do not override self when calling methods from the same object.

Conclusion:

The self parameter is a cornerstone of object-oriented programming in Python. It ensures that methods operate on the correct instance, maintaining data integrity and enabling object-specific behavior.

Desktop Virtualisation

Desktop Virtualization ( DV ) Desktop Virtualization ( DV ) is a technique that creates an illusion of a desktop provided to the user. It d...