0% found this document useful (0 votes)
6 views

adv python

The document provides an overview of Python data structures including lists, dictionaries, tuples, and sets, detailing their characteristics and operations. It also covers functions, exceptions, lambda functions, parallel processing, and the use of the map and filter functions. Additionally, it introduces classes as user-defined data types, explaining their structure and how to create objects.

Uploaded by

Anshu Yadav
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
6 views

adv python

The document provides an overview of Python data structures including lists, dictionaries, tuples, and sets, detailing their characteristics and operations. It also covers functions, exceptions, lambda functions, parallel processing, and the use of the map and filter functions. Additionally, it introduces classes as user-defined data types, explaining their structure and how to create objects.

Uploaded by

Anshu Yadav
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 23

UNIT -1

Data Structures: Problem solving using Python Data Structures: LIST, DICT, TUPLES and SET-
Functions and Exceptions – Lamda Functions and Parallel processing – MAPS – Filtering - Itertools – Generators.

Data Structures and Problem-Solving Using Python


Python provides several built-in data structures that help efficiently store and manipulate data. The primary ones include
lists, dictionaries, tuples, and sets. These structures play a crucial role in problem-solving, enabling efficient algorithms.

1. LIST
A list is an ordered, mutable collection of elements that allows duplicates. It is one of the most commonly used data
structures in Python.
Characteristics:
· Ordered: Elements maintain their insertion order.
· Mutable: Items can be modified (added, removed, or changed).
· Allows Duplicates: The same value can appear multiple times.
· Indexing & Slicing Supported: Elements can be accessed via indexes.
· Can Contain Different Data Types: A list can store integers, strings, other lists, etc.

Operations on List:
Operation Description Example Output
Creation Define a list lst = [1, 2, 3, 4] [1, 2, 3, 4]
Accessing Elements Retrieve elements using an index lst[0] 1
Slicing Get a subset of the list lst[1:3] [2, 3]
Append Add an element at the end lst.append(5) [1, 2, 3, 4, 5]
Insert Insert at a specific index lst.insert(2, 10) [1, 2, 10, 3, 4]
Remove Remove first occurrence of a value lst.remove(2) [1, 10, 3, 4]
Pop Remove element at index (default last) lst.pop(1) [1, 3, 4]
Reverse Reverse list order lst.reverse() [4, 3, 1]
Sort Sort the list lst.sort() [1, 3, 4]
Length Get the number of elements len(lst) 3

2. Dictionary
A dictionary is an unordered, mutable collection of key-value pairs, where each key is unique.
· Unordered (before Python 3.7), but maintains insertion order from Python 3.7+.
· Mutable: Keys and values can be modified.
· Keys Must Be Unique: No duplicate keys are allowed.
· Keys Must Be Immutable: Strings, numbers, and tuples can be keys.
· Efficient Lookup: Provides fast key-based access.

Operation Description Example Output


Creation Define a dictionary dct = {"name": "Alice", "age": 25} {'name': 'Alice', 'age': 25}
Accessing Values Get value by key dct["name"] "Alice"
Get Method Retrieve value with default dct.get("age", 0) 25
Add/Update Add or modify key-value pair dct["city"] = "NY" {'name': 'Alice', 'age': 25, 'city': 'NY'}
Delete Key Remove a key del dct["age"] {'name': 'Alice', 'city': 'NY'}
Pop Remove and return value dct.pop("name") 'Alice'
Keys Get all keys dct.keys() dict_keys(['age', 'city'])
Values Get all values dct.values() dict_values([25, 'NY'])
Items Get key-value pairs dct.items() dict_items([('age', 25), ('city', 'NY')])

3. Tuple
A tuple is an ordered, immutable collection of elements that allows duplicates.
· Ordered: Elements maintain their insertion order.
· Immutable: Once created, elements cannot be modified.
· Allows Duplicates: The same value can appear multiple times.
· Faster than Lists: Tuples provide better performance for read-only operations.
Operation Description Example Output
Creation Define a tuple tpl = (1, 2, 3, 4) (1, 2, 3, 4)
Accessing Elements Retrieve elements using an index tpl[0] 1
Slicing Get a subset of the tuple tpl[1:3] (2, 3)
Length Get the number of elements len(tpl) 4
Count Count occurrences of a value tpl.count(2) 1
Index Find the first occurrence of a value tpl.index(3) 2
Concatenation Merge two tuples tpl + (5, 6) (1, 2, 3, 4, 5, 6)
Unpacking Assign values to variables a, b, c, d = tpl a=1, b=2, c=3, d=4

4. Set
A set is an unordered collection of unique elements.
· Unordered: Elements do not follow a specific sequence.
· Mutable: Can add or remove elements, but individual elements cannot be changed.
· No Duplicates: Automatically removes duplicate values.
· Supports Mathematical Operations: Intersection, union, difference, etc.

Operation Description Example Output


Creation Define a set st = {1, 2, 3, 4} {1, 2, 3, 4}
Add Add an element st.add(5) {1, 2, 3, 4, 5}
Remove Remove a specific element st.remove(2) {1, 3, 4, 5}
Discard Remove element without error st.discard(10) No error
Pop Remove and return a random element st.pop() Removes an arbitrary element
Union Merge two sets st.union({6, 7}) {1, 3, 4, 5, 6, 7}
Intersection Common elements in two sets st.intersection({3, 4, 7}) {3, 4}
Difference Elements in one set but not another st.difference({3, 4}) {1, 5}
Subset Check if one set is a subset of another {1, 3}.issubset(st) True

FUNCTIONS
A function is a self-contained block of code that performs a specific task.
 Functions promote code reuse, modularity, and readability.
 Python has:
o Built-in functions like print(), len(), max()
o User-defined functions which you can create with def
o Anonymous functions (lambda functions)
Syntax of a Function
def function_name(parameters):
"""docstring (optional)"""
# body
return value

Key Concepts:
Concept Description
def Keyword to define a function
Parameters Input values (optional)
return Output value (optional)
Docstring Describes what the function does

1. Defining a Function
def greet(name):
return f"Hello, {name}!"
#You can now call this function:
print(greet("Alice")) # Output: Hello, Alice!

2. Function with Default Parameter

def greet(name="Friend"):
return f"Hello, {name}!"
print(greet()) # Hello, Friend

3. Function with Multiple Parameters


def add(a, b):
return a + b
print(add(2, 3)) # Output: 5

4. Return Multiple Values


def calc(a, b):
return a + b, a - b

add, sub = calc(5, 3)


print(add, sub) # Output: 8 2

5. Variable-Length Arguments
def total_sum(*args): # any number of positional arguments
return sum(args)

print(total_sum(1, 2, 3, 4)) # Output: 10

EXCEPTIONS – Error Handling in Python


An exception is an event or error that occurs during the execution of a program, disrupting the normal flow of
instructions.
In programming, exceptions are used to handle errors gracefully without crashing the program. For example, trying to
divide a number by zero or accessing an invalid index in a list can raise an exception.

Common Exceptions:
Exception Description Code Example
SyntaxError Code has incorrect syntax. # print("Hello"
NameError Using a variable that hasn't been defined. print(x) when x is not defined
TypeError Operation or function applied to the wrong type. '2' + 2
IndexError Accessing an index that doesn’t exist. [1, 2][5]
KeyError Accessing a dictionary key that doesn't exist. {"a": 1}["b"]
ValueError Correct type, but inappropriate value. int("abc")
ZeroDivisionError Dividing a number by zero. 10 / 0
FileNotFoundErro Trying to open a file that doesn't exist. open("no.txt")
r
AttributeError Invalid attribute access for an object. 10.append(5)
ImportError Import fails because module doesn't exist. import fake_module
IndentationError Incorrect indentation in the code. def f():\nprint("Hi")
RuntimeError Errors that don't fall into other categories. Recursive call with no base
case

Handling Exceptions
Exception handling is a mechanism in Python that allows you to deal with runtime errors (exceptions) in a controlled
manner. When an error occurs, it raises an exception which interrupts the normal flow of the program. By using exception
handling, you can catch and handle these exceptions, allowing the program to continue running smoothly or give
meaningful feedback to the user.
Syntax :
try: # This is where you write code that may raise an exception
except SomeException as e: # This block handles the exception
else: # This block runs if no exception occurs
finally: # This block will always run, regardless of whether an exception occurred

Example:
try:
num1 = int(input("Enter the numerator: "))
num2 = int(input("Enter the denominator: "))
result = num1 / num2

except ZeroDivisionError:
print("You cannot divide by zero.")

except ValueError:
print("Please enter valid integers.")

else:
print("The result is:", result)

finally:
print("Program execution completed.")

LAMBDA FUNCTIONS – Anonymous Functions


A lambda function in Python is a small, anonymous function that is defined using the keyword lambda. Unlike regular
functions defined using def, lambda functions are used for short, simple operations and are defined in a single line.
 It can have any number of arguments but only one expression.
 Often used for quick operations especially in functional programming tools like map(), filter(), and reduce().

Syntax: lambda arguments: expression


arguments: The input parameters (can be zero or more).
expression: A single expression whose result is returned.

Why Use Lambda Functions?


 For short operations
 When you don’t want to define a full function using def
 Used as quick helpers for functions like:
o map(): Apply a function to all items
o filter(): Filter items using a condition sorted(): Sort with custom logic

Examples: 1. Simple lambda function:


add = lambda x, y: x + y
print(add(5, 3)) # Output: 8

2. Using lambda with map():


nums = [1, 2, 3, 4]
squares = list(map(lambda x: x**2, nums))
print(squares) # Output: [1, 4, 9, 16]

3. Using lambda with filter():


nums = [1, 2, 3, 4, 5, 6]
evens = list(filter(lambda x: x % 2 == 0, nums))
print(evens) # Output: [2, 4, 6]

4: Lambda with sorted()


data = [(1, 2), (3, 1), (5, 4), (4, 2)]
sorted_data = sorted(data, key=lambda x: x[1])
print(sorted_data) # Output: [(3, 1), (1, 2), (4, 2), (5, 4)]
PARALLEL PROCESSING
Parallel processing is the technique of performing multiple tasks simultaneously, making full use of multi-core
processors. It increases execution speed by running tasks at the same time instead of one after another.

Sequential vs Parallel:
 Sequential: Tasks are performed one after the other
 Parallel: Tasks are split and run simultaneously on different processors/cores

Python Module Used: multiprocessing — built-in module that allows the creation of separate processes

Steps to Use Parallel Processing:


1. Import multiprocessing 2. Define a function 3. Create a process object
4. Start the process 5. Join the processes (optional)
Example:
import multiprocessing
import time

def print_numbers():
for i in range(5):
print(i)
time.sleep(1)

if __name__ == "__main__":
p1 = multiprocessing.Process(target=print_numbers)
p2 = multiprocessing.Process(target=print_numbers)

p1.start()
p2.start()

p1.join()
p2.join()
This runs print_numbers() in two separate processes at the same time.

Real-World Use Cases:


 Web servers handling multiple requests
 Data processing in AI/ML
 Downloading multiple files at once

map() FUNCTION
map() is used to apply a function to every item in an iterable (like a list or tuple). It returns a map object, which is an
iterator. Ideal for transforming data without using loops.

SYNTAX: map(function, iterable)

EXAMPLE: using map() to convert a list of strings into a list of integers.


s = ['1', '2', '3', '4']
res = map(int, s)
print(list(res))

filter() FUNCTION
filter() is used to filter out elements from an iterable based on a condition (True/False). It removes items that do not
meet a condition.
SYNTAX: filter(function, iterable)

def even(n): # Function to check if a number is even


return n % 2 == 0

a = [1, 2, 3, 4, 5, 6]
b = filter(even, a)

print(list(b)) # Convert filter object to a list


What's happening? Only values where x % 2 == 0 is True are kept.
itertools MODULE

GENERATORS
A generator is a special function that returns an iterator and generates items one at a time using the yield keyword.
Memory-efficient and ideal for large data sequences or infinite loops.

SYNTAX:
def my_generator():
yield value

EXAMPLE:
def countdown(n):
while n > 0:
yield n
n -= 1

for val in countdown(5):


print(val)
# Output: 5 4 3 2 1 in different lines
The yield pauses the function and resumes from where it left off next time.

Differences: Generator vs Function


Aspect Function Generator
Keyword return yield
Return All values at once One value at a time
Memory Uses more memory Memory efficient
Performanc Slower for large Faster for large data
e data

Classes & Objects: Classes as User Defined Data Type, Objects as Instances of Classes, Creating Class and
Objects, Creating Objects by Passing Values, Variables & Methods in a Class Data, Abstraction, Data Hiding,
Encapsulation, Modularity, Inheritance, Polymorphism

CLASS
A class in Python is a blueprint for creating objects. Objects are instances that contain data (attributes) and functions
(methods) to operate on that data. A User Defined Data Type is a data structure created by the programmer to represent
real-world entities.

Why Create User-Defined Data Types?


Built-In Types like int, float, list are good, but not enough to represent complex things like:
 A Student with name, roll number, and marks.
 A Car with brand, color, speed.
 A BankAccount with account number, balance, holder name.
We need a way to group related data and behaviors — that’s where classes come in.

Structure Of A Class (User Defined Data Type)


class ClassName:
def __init__(self, parameters): # Constructor
self.attribute1 = value1
self.attribute2 = value2

def method1(self):
# Some behavior
pass
 class keyword defines a class.
 __init__() is the constructor. It runs when you create an object.
 self refers to the current object.
 You define attributes and methods inside it.

EXAMPLE: STUDENT CLASS


class Student:
def __init__(self, name, roll, marks):
self.name = name
self.roll = roll
self.marks = marks

def display(self):
print("Name:", self.name)
print("Roll No:", self.roll)
print("Marks:", self.marks)
Here, Student is a user-defined data type with:
 Data (name, roll, marks)
 Behavior (display())

Creating objects (instances)


s1 = Student("Alice", 101, 95)
s2 = Student("Bob", 102, 87)

s1.display()
s2.display()

OUTPUT:
Name: Alice
Roll No: 101
Marks: 95
Name: Bob
Roll No: 102
Marks: 87

key concepts
Term Description
Class Blueprint for creating objects (user-defined type)
Object Instance of a class (holds data + functions)
Attribute Variables in class (e.g., name, roll)
Method Functions defined inside a class
Constructor Special method that runs when the object is created
(__init__)
Self Reference to the current object

Benefits of using classes


 Modularity: Code is grouped in logical pieces.
 Reusability: Same class can be used to make many objects.
 Maintainability: Easier to manage, debug, and extend.
 Real-world modeling: Can represent students, cars, books, etc.

OBJECTS AS INSTANCES OF CLASSES


An object is a real-world entity that has:
 Attributes (characteristics or data)
 Behaviors (functions or methods)

Instance -- Another name for an object – every object is an instance of a class


Analogy: Imagine a class like a cookie cutter.It defines the shape (structure) of cookies. Every cookie made from that
cutter is an object (instance of the class).
Creating Objects Syntax: object_name = ClassName(arguments)
When you call the class like a function, Python invokes the __init__ method to initialize the object.

Example: student class


Step 1: define a class
class Student:
def __init__(self, name, roll):
self.name = name
self.roll = roll

def display(self):
print(f"Name: {self.name}, Roll: {self.roll}")

Step 2: Create Objects (Instances)


s1 = Student("Alice", 101) # Object 1
s2 = Student("Bob", 102) # Object 2

Step 3: Use the Object


s1.display() # Output: Name: Alice, Roll: 101
s2.display() # Output: Name: Bob, Roll: 102
Each object behaves independently based on the values passed during creation.

Object Attributes
You can also access or modify attributes directly:
print(s1.name) # Alice
s1.name = "Alicia"
print(s1.name) # Alicia

Why Objects Are Important?


 They allow modular, reusable, and organized code.
 They mimic real-world entities (student, car, bank account, etc.).
 OOP enables features like encapsulation, inheritance, polymorphism.

CREATING A CLASS
A class is a blueprint for creating objects. It defines attributes (variables) and methods (functions).
Syntax:
class ClassName:
def __init__(self): # Constructor
# attributes
def method_name(self):
# behavior
 __init__() is a constructor. It runs automatically when the object is created.
 self refers to the current object (like this in other languages).

Example: Basic Class


class Person:
def __init__(self): # Constructor without parameters
print("A new person is created!")

CREATING OBJECTS
An object is an instance of a class.
Syntax: obj = ClassName()
Example:
p1 = Person()
p2 = Person()
Output:
A new person is created!
A new person is created!
Each time you call the class, it creates a new object and runs the constructor.

CREATING OBJECTS BY PASSING VALUES


You can pass arguments to the constructor using __init__().
Example: Class with Parameters
class Person:
def __init__(self, name, age): # Constructor with parameters
self.name = name
self.age = age

def display(self):
print(f"Name: {self.name}, Age: {self.age}")

Creating Objects with Values


p1 = Person("Alice", 25)
p2 = Person("Bob", 30)

p1.display() # Output: Name: Alice, Age: 25


p2.display() # Output: Name: Bob, Age: 30

Why Passing Values is Useful?


It allows each object to have custom values.
Enables dynamic creation of different objects.
Makes classes reusable and flexible.

VARIABLE
Variables are used to store data related to the class or its instances. Variables inside a class can be of two types:

Instance Variable : belong to each object, Unique for every object .


Class variable : Shared across all objects of the class.

Instance Variable (Object-level variable)


 Defined using self.variable_name inside the constructor or other methods. Unique to each instance (object).
 An instance variable is defined using self.variable_name inside methods (typically in __init__).
 Scope: Unique to each individual object (instance).
 Usage: Used to store data specific to each object.
Class Variable (Shared among all instances)
 Defined outside any method but inside the class. Shared across all objects.
 Scope: Shared by all instances of the class.
 Usage: Used for data that should be common for all objects.
Example:
class Student:
school_name = "ABC School" # Class variable

def __init__(self, name):


self.name = name # Instance variable

s1 = Student("Alice")
s2 = Student("Bob")

print(s1.school_name) # ABC School


print(s2.school_name) # ABC School
METHOD
A method is a function that is defined inside a class and is used to perform operations related to objects (instances) of
that class. It automatically takes the instance (self) or class (cls) as the first parameter, depending on the method type.

Types of Methods:
Type Defined with Access
Instance Method self Can access both instance & class variables
Class Method @classmethod + cls Can access only class variables
Static Method @staticmethod Cannot access self or cls

1. Instance Method
 Definition: Operates on instance variables of the object.
 First parameter: Always self.
 Usage: Most common type; used to access or modify object-specific data.
class Student:
def __init__(self, name):
self.name = name

def display(self): # Instance method


print("Name:", self.name)

2. Class Method
 Definition: Operates on the class variables; affects all instances.
 First parameter: Always cls. Decorator: @classmethod
class Student:
school = "ABC School"

@classmethod
def change_school(cls, new_name): # Class method
cls.school = new_name

3. Static Method
 Definition: Does not access instance or class data; behaves like a regular function inside a class.
 No self or cls parameter Decorator: @staticmethod
class MathTools:
@staticmethod
def add(a, b): # Static method
return a + b

Real-Life Analogy
Imagine a "Student" class:
 Each student has a name and age → instance variables.
 All students go to "XYZ School" → class variable.
 Each student can introduce themselves → instance method.
 The school name can be updated for everyone → class method.
 A static method can be used to check if a student is eligible (like age >= 18) → static method.

ABSTRACTION
Abstraction is the process of hiding internal details and showing only essential information to the user.
 Focuses on what an object does, rather than how it does it.
 Achieved using abstract classes and interfaces (in Python: via abc module).

Real-Life Example: Think about a TV remote:


 You press buttons to change channels or volume.
 But you don’t know (or need to know) how the remote sends signals or interacts with the TV internally.
This is abstraction — hiding the complex implementation and exposing only the necessary interface.

Why Use Abstraction?


Focus Hide complexity and show only relevant details.
Security Prevent direct access to internal logic.
Use abstract templates for different implementations.
Reusability
Flexibility Allows changes in implementation without affecting usage.
How is Abstraction Achieved in Python?
Python achieves abstraction through:
1. Abstract Classes
 Created using the abc module (abc stands for Abstract Base Class).
 Cannot be instantiated directly.
 Can have abstract methods (methods without implementation).
2. Abstract Methods
 Defined using the @abstractmethod decorator.
 Must be implemented in the child class, or an error will occur.
Example
from abc import ABC, abstractmethod

# Abstract Class
class Animal(ABC):

@abstractmethod
def sound(self):
pass

# Subclass must implement the abstract method


class Dog(Animal):
def sound(self):
return "Bark"

class Cat(Animal):
def sound(self):
return "Meow"

# Using the classes


d = Dog()
print(d.sound()) # Output: Bark

c = Cat()
print(c.sound()) # Output: Meow

Explanation of your code:


1. Animal is an abstract class with an abstract method sound().
2. Dog and Cat are subclasses that provide their own implementation of sound().
3. You cannot create an object of Animal directly because it's abstract.
4. But you can use it to enforce a structure on all its subclasses.
Concept Meaning
Abstract Class Blueprint that cannot be instantiated directly
Abstract Method Method without a body — must be
overridden
Module Used abc in Python
Purpose Hide complexity, enforce rules

DATA HIDING
Data Hiding is an OOP concept used to restrict direct access to some of an object's components (like variables), for
security and data integrity.
It prevents the accidental modification of data and ensures controlled access.

Real-Life Analogy:
Think of a bank account:
 You can see your balance using an app (interface).
 But you can’t directly access or modify the account data in the bank’s system — it’s protected.
 Any update has to go through proper methods (like deposit or withdraw).
That’s data hiding in action!

Why is Data Hiding Important?


Benefit Description
Security Protects sensitive data from unauthorized
access
Control Allows validation before changing variables
Simplicity Hides complexity and reduces user errors
Maintainabilit Makes programs easier to maintain and update
y

Data Hiding in Python


Python uses naming conventions to hide data:
Syntax Meaning
variable Public (accessible from anywhere)
_variable Protected (suggested to use only within class or
subclass)
__variable Private (name mangling is applied, limited access)

Example: Data Hiding in Action


class Employee:
def __init__(self, name, salary):
self.name = name # Public attribute
self.__salary = salary # Private attribute

def display_info(self): # Public method


print(f"Name: {self.name}")
print(f"Salary: {self.__salary}")

def __private_method(self): # Private method


print("This is a private method!")

e = Employee("John", 50000)

e.display_info()
Private Variable: self.__salary is a private variable. It can't be accessed directly from outside the class.
Public Method: The display_info() method is a public method and can be called from outside the class to access
information.
Private Method: __private_method() is a private method. It can only be accessed within the class, not from outside.
Access Control: If you try to directly access the private variable __salary outside the class (e.g., e.__salary), Python will
raise an AttributeError.

ENCAPSULATION
Encapsulation is the concept of wrapping data (variables) and methods (functions) that operate on the data within a
single unit — the class. It helps to restrict direct access to some of the object’s components and provides controlled
access via methods.
Real-Life Analogy:
Think of a capsule (medicine):
 It contains a mixture of drugs (data + operations) inside a shell.
 You don’t see the individual components — you just take the capsule.
 Similarly, in programming, a class encapsulates data and functions.

Why Use Encapsulation?


Benefit Description
Security Prevents unauthorized access to internal
data
Code Organization Bundles related data and behavior
Cleaner Code Hides complexity from the user
Reusability Encourages modular and reusable code

Encapsulation in Python
 Use classes to encapsulate data and functions.
 Use access modifiers:
o public: accessible from anywhere
o protected (_var): suggest restricted use
o private (__var): name-mangled, not directly accessible
Example
class Person:
def __init__(self, name, age):
self.__name = name # Private attribute
self.__age = age # Private attribute

def get_details(self): # Public method to access private attributes


return f"Name: {self.__name}, Age: {self.__age}"

# Create an object and access details


p = Person("Alice", 30)
print(p.get_details())

Explanation:
1. Private Attributes: __name and __age are private attributes of the Person class.
2. Public Method: get_details() is a public method used to access the private attributes safely.
3. Encapsulation: The class encapsulates the data (name and age) and allows controlled access via the get_details()
method, protecting the internal data from direct modification

Difference Between Data Hiding & Encapsulation:


Concept Description
Data Hiding Restricting access to internal data
Encapsulatio Bundling data + behavior inside a class, and restricting access
n
Encapsulation uses data hiding as one of its tools.

MODULARITY
Modularity is the concept of breaking a large program into smaller, manageable, reusable, and independent
components called modules.
Each module contains everything necessary to execute one aspect of the desired functionality.

Real-Life Analogy: Think of a car:


 The engine, transmission, brakes, and steering system are all separate modules.
 You can repair or upgrade one part without affecting others.
 Together, they make the complete system work.
The same idea applies in programming — breaking down a large system into parts that work together.

Why Use Modularity?

 Easier to maintain: Fix bugs in one module without affecting others


 Reusability: Reuse modules in different programs.
 Better organization: Keep code clean, structured, and easy to read
 Collaboration: Multiple developers can work on different modules

In Python, modules are simply .py files that contain classes, functions, or variables.
You can import and use them in other files.

Example:
# Module: operations.py
def multiply(a, b): return a * b

# Main code
import operations

result = operations.multiply(3, 4)
print("Product:", result)
Explanation:
1.Modular Code: The multiplication function is defined in a separate module (operations.py), keeping the code organized.
2. Main Program: The main code imports the operations module and uses its multiply() function to compute the result.
3. Reusability: The operations module can be reused across different programs, demonstrating modularity.
Modularity vs Other OOP Concepts
Concept What It Does
Encapsulation Bundles data + methods in a class
Abstraction Hides complexity; shows only essentials
Modularity Breaks system into manageable pieces
Inheritance Enables reusability from parent to child
Polymorphism Same method behaves differently in
classes

INHERITANCE
Inheritance is an Object-Oriented Programming (OOP) concept where a child class (subclass) inherits attributes and
methods from a parent class (superclass).
This allows code reuse and makes it easier to maintain and scale programs.

Real-Life Analogy:
Imagine a parent has certain characteristics, like a surname, and habits.
Their child inherits many of these traits — but can also have some of their own! In programming, the child class gets
access to the parent class properties and behaviors, but can also add or override them.

Why Use Inheritance?


1. Code Reusability: Child classes can reuse methods and variables from the parent class, reducing redundancy.
2. Organization: Keeps common functionality in the parent class and specialized logic in the child class.
3. Extensibility: Easily extend features in child classes without changing the parent class.
4. Maintainability: Fixes in the parent class automatically apply to all child classes.

Basic Example:
# Parent Class
class Animal:
def __init__(self, name):
self.name = name

def speak(self):
print(f"{self.name} makes a sound.")

# Child Class
class Dog(Animal):
def speak(self):
print(f"{self.name} barks!")

# Using the classes


a = Animal("Generic Animal")
a.speak()

d = Dog("Tommy")
d.speak()
Explanation:
 Dog inherits from Animal
 It gets __init__() from the parent class
 But it overrides the speak() method
POLYMORPHISM
Polymorphism is an OOP concept that allows objects of different classes to be treated as objects of a common
superclass. It also allows the same method to behave differently depending on the object calling it.
In simpler terms:
 One interface, multiple behaviors.
 It allows the same method name to behave differently based on the object type.

Real-Life Analogy:
Think of a shape:
 You have a generic shape that can have a draw() method.
 But you also have circle, rectangle, and triangle subclasses.
 Each subclass has its own way of drawing.
class Shape:
def draw(self):
print("Drawing a generic shape")

class Circle(Shape):
def draw(self):
print("Drawing a Circle")

class Rectangle(Shape):
def draw(self):
print("Drawing a Rectangle")

shapes = [Circle(), Rectangle(), Shape ()]


for shape in shapes:
shape.draw()
Why Use Polymorphism?
1. Flexibility: New classes can be added without altering existing code.
2. Code Reusability: Same method name works for different objects.
3. Simplicity: Reduces complexity with one interface for multiple behaviors.

1. Compile-Time Polymorphism (Method Overloading):


Python doesn't support method overloading directly like some other languages. However, you can achieve similar
behavior using default arguments or variable-length arguments.
class Greet:
def say_hello(self, name=None):
if name:
print(f"Hello, {name}!")
else:
print("Hello, world!")

g = Greet()
g.say_hello() # Calls with no arguments
g.say_hello("Alice") # Calls with one argument
Explanation: This is a simple way of simulating method overloading by using default arguments.

2. Runtime Polymorphism (Method Overriding):


In Python, method overriding occurs when a child class provides its own implementation of a method that is already
defined in the parent class.

Example of Runtime Polymorphism: (polymorphism shape ex)

Unit 2
Python Mulithreading : Python Multithtreading and Multiprocessing ant their basics- Threading module and
example, multithreaded priority queue

Python Multithtreading
A thread is an entity within a process that can be scheduled for execution. Also, it is the smallest
unit of processing that can be performed in an OS (Operating System). In simple words, a thread is
a sequence of such instructions within a program that can be executed independently of other
code. For simplicity, you can assume that a thread is simply a subset of a process! A thread
contains all this information in a Thread Control Block (TCB) :

 Thread Identifier: Unique id (TID) is assigned to every new thread


 Stack pointer: Points to the thread's stack in the process. The stack contains the local variables
under the thread's scope.
 Program counter: a register that stores the address of the instruction currently being executed
by a thread.
 Thread state: can be running, ready, waiting, starting, or done.
 Thread's register set: registers assigned to thread for computations.
 Parent process Pointer: A pointer to the Process control block (PCB) of the process that the
thread lives on.

Relationship between a Process and its Thread


Existence of multiple threads in memory

Multithreading is defined as the ability of a processor to execute multiple threads concurrently. In a simple,
single-core CPU, it is achieved using frequent switching between threads. This is termed context switching .
In context switching, the state of a thread is saved and the state of another thread is loaded whenever any
interrupt (due to I/O or manually set) takes place. Context switching takes place so frequently that all the
threads appear to be running parallelly (this is termed multitasking ). In Python , the threading module
provides a very simple and intuitive API for spawning multiple threads in a program.
Steps for creating thread in multithreading:-
Step 1: Import Module
First, import the threading module.
import threading
Step 2: Create a Thread
To create a new thread, we create an object of the Thread class. It takes the 'target' and 'args' as the
parameters. The target is the function to be executed by the thread whereas the args is the arguments to be
passed to the target function.
t1 = threading.Thread(target, args)
t2 = threading.Thread(target, args)
Step 3: Start a Thread
To start a thread, we use the start() method of the Thread class.
t1.start()
t2.start()
Step 4: End the thread Execution
Once the threads start, the current program (you can think of it like a main thread) also keeps on executing. In
order to stop the execution of the current program until a thread is complete, we use the join() method.
t1.join()
t2.join()
As a result, the current program will first wait for the completion of t1 and then t2 . Once, they are finished,
the remaining statements of the current program are executed.

Example:-
import threading

def print_cube(num):
print("Cube: {}" .format(num * num * num))

def print_square(num):
print("Square: {}" .format(num * num))
if __name__ =="__main__":
t1 = threading.Thread(target=print_square, args=(10,))
t2 = threading.Thread(target=print_cube, args=(10,))

t1.start()
t2.start()

t1.join()
t2.join()

print("Done!")

Output
Square: 100

Cube: 1000

Done!

multithreaded priority queue

A priority queue is like a regular queue, but each item has a priority. Instead of being served in the order they
arrive, items with higher priority are served first. For example, In airlines, baggage labeled “Business” or
“First Class” usually arrives before the rest.
Key properties of priority queue:
 High-priority elements are dequeued before low-priority ones.
 If two elements have the same priority, they are dequeued in their order of insertion like a queue.

The multithreaded Queue module is primarily used to manage to process large amounts of data on multiple
threads. It supports the creation of a new queue object that can take a distinct number of items.
The get() and put() methods are used to add or remove items from a queue respectively. Below is the list of
operations that are used to manage Queue:
 get(): It is used to add an item to a queue.
 put(): It is used to remove an item from a queue.
 qsize(): It is used to find the number of items in a queue.
 empty(): It returns a boolean value depending upon whether the queue is empty or not.
 full(): It returns a boolean value depending upon whether the queue is full or not.

Example:
import queue
import threading
import time

thread_exit_Flag = 0

class sample_Thread (threading.Thread):


def __init__(self, threadID, name, q):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
self.q = q
def run(self):
print ("initializing " + self.name)
process_data(self.name, self.q)
print ("Exiting " + self.name)

# helper function to process data


def process_data(threadName, q):
while not thread_exit_Flag:
queueLock.acquire()
if not workQueue.empty():
data = q.get()
queueLock.release()
print ("% s processing % s" % (threadName, data))
else:
queueLock.release()
time.sleep(1)

thread_list = ["Thread-1", "Thread-2", "Thread-3"]


name_list = ["A", "B", "C", "D", "E"]
queueLock = threading.Lock()
workQueue = queue.Queue(10)
threads = []
threadID = 1

# Create new threads


for thread_name in thread_list:
thread = sample_Thread(threadID, thread_name, workQueue)
thread.start()
threads.append(thread)
threadID += 1

# Fill the queue


queueLock.acquire()
for items in name_list:
workQueue.put(items)

queueLock.release()

# Wait for the queue to empty


while not workQueue.empty():
pass

# Notify threads it's time to exit


thread_exit_Flag = 1

# Wait for all threads to complete


for t in threads:
t.join()
print ("Exit Main Thread")
Output:
initializing Thread-1

initializing Thread-2initializing Thread-3

Thread-2 processing AThread-3 processing B

Thread-3 processing C
Thread-3 processing D

Thread-2 processing E

Exiting Thread-2

Exiting Thread-1

Exiting Thread-3

Exit Main Thread

Threading module and example

The threading module in Python facilitates the creation and management of threads, enabling concurrent
execution of tasks within a program. A thread represents an independent flow of execution, allowing multiple
operations to occur seemingly simultaneously. While Python's Global Interpreter Lock (GIL) restricts true
parallelism in CPU-bound tasks, threading is beneficial for I/O-bound operations, such as network requests or file
handling, where threads can efficiently utilize waiting times.
Key Features and Concepts
Thread Creation:
The threading.Thread class is used to create new threads. A target function is specified, which the thread will execute
upon starting.
Thread Management:
Methods like start(), join(), and is_alive() control thread execution and synchronization. start() initiates the
thread, join() waits for the thread to complete, and is_alive() checks if the thread is currently running.
Synchronization:
The threading module provides tools for managing shared resources and preventing race conditions, such as locks
(threading.Lock), semaphores (threading.Semaphore), and condition variables ( threading.Condition).
Daemon Threads:
Threads can be set as daemon threads, meaning they will automatically terminate when the main program exits,
regardless of their execution status.
Thread Pools:
The concurrent.futures module offers ThreadPoolExecutor for managing a pool of worker threads, simplifying the execution
of multiple tasks concurrently.
Example
import threading
import time

def task(name):
print(f"Thread {name}: starting")
time.sleep(2)
print(f"Thread {name}: finishing")

if __name__ == "__main__":
threads = []
for i in range(3):
thread = threading.Thread(target=task, args=(i,))
threads.append(thread)
thread.start()

for thread in threads:


thread.join()
print("All tasks completed")

In this example, three threads are created and started, each executing the task function. The join() method ensures
that the main program waits for all threads to finish before exiting.
Multiprocessing

Multiprocessing refers to the ability of a system to support more than one processor at the same time.
Applications in a multiprocessing system are broken to smaller routines that run independently. The
operating system allocates these threads to the processors improving performance of the system.
multiprocessing module which enables the systems to run multiple processes simultaneously. In other words,
developers can break applications into smaller threads that can run independently from their Python code.
These threads or processes are then allocated to the processor by the operating system, allowing them to run in
parallel, improving your Python programs' performance and efficiency. Multiprocessing refers to using multiple
CPUs/processors in a single system. Multiple CPUs can act in a parallel fashion and execute multiple processes together.
A task is divided into multiple processes that run on multiple processors. When the task is over, the results from all
processors are compiled together to provide the final output. Multiprocessing increases the computing power to a great
extent. Symmetric multiprocessing and asymmetric multiprocessing are two types of multiprocessing.
Multiprocessing increases the reliability of the system because of the use of multiple CPUs. However, a significant
amount of time and specific resources are required for multiprocessing. Multiprocessing is relatively more cost effective
as compared to a single CPU system.When we work with Multiprocessing , at first we create process object. Then it calls
a start() method.Consider a computer system with a single processor. If it is assigned several processes at the same
time, it will have to interrupt each task and switch briefly to another, to keep all of the processes going. This situation
is just like a chef working in a kitchen alone. He has to do several tasks like baking, stirring, kneading dough, etc. So
the gist is that: The more tasks you must do at once, the more difficult it gets to keep track of them all, and keeping the
timing right becomes more of a challenge. This is where the concept of multiprocessing arises.

Example
from multiprocessing import Process
def cube(x):
for x in my_numbers:
print('%s cube is %s' % (x, x**3))
if __name__ == '__main__':
my_numbers = [3, 4, 5, 6, 7, 8]
p = Process(target=cube, args=('x',))
p.start()
p.join
print ("Done")
Functions performed by multiprocessing:-
Locks

When we want that only one process is executed at a time in that situation Locks is use. That means that time blocks other
process from executing similar code. Lock will be released after the process gets completed.
Logging

The multiprocessing module also provides logging module to ensure that, if the logging package doesn't use locks
function, the messages between processes mixed up during execution.
Pipes

In multiprocessing, when we want to communicate between processes, in that situation Pipes are used.
Queues

When we pass data between processes then at that time we can use Queue object.

Factor Multiprocessing Multithreading

Multiple processors/CPUs are Multiple threads are created of a


added to the system to process to be executed in a
Concept
increase the computing power parallel fashion to increase the
of the system. throughput of the system.

Parallel Multiple processes are Multiple threads are executed in


Action executed in a parallel fashion. a parallel fashion.

Multiprocessing can be
No such classification present for
Categories classified into symmetric and
multithreading.
asymmetric multiprocessing.

Process creation is time- Thread creation is easy and is


Time
consuming. time savvy.

In multiprocessing, many
In multithreading, many threads
Execution processes are executed
are executed simultaneously.
simultaneously.

In multiprocessing, a separate In multithreading, a common


Address
address space is created for address space is used for all the
space
each process. threads.

Multiprocessing requires a
Multithreading requires less time
Resources significant amount of time and
and few resources to create.
large number of resources.
Handling CSV file:-
CSV (Comma Separated Values) is a simple file format used to store tabular data, such as a spreadsheet or database. A
CSV file stores tabular data (numbers and text) in plain text. Each line of the file is a data record. Each record consists
of one or more fields, separated by commas. The use of the comma as a field separator is the source of the name for
this file format. For working CSV files in Python, there is an inbuilt module called CSV.

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy