University Course โข EduArtha
Python Programming
Master Python from scratch โ variables, control flow, functions, OOP, file handling, and regular expressions. Includes 15 complete lab experiments with solutions.
๐ 6 Units | 14 Chapters | 15 Lab Programs | Complete Solutions
Setting Up Your Programming Environment
Python installation, variables, expressions & statements
Setting Up & Hello World
Learning Objectives
- Understand Python versions and choose the right one
- Install Python on Windows and configure PATH
- Write and run your first Python program
- Use IDLE, VS Code, and the command line
- Master the print() and input() functions
1.1 What is Python?
Python is a high-level, interpreted, general-purpose programming language created by Guido van Rossum in 1991. It emphasizes code readability with its clean syntax and indentation-based block structure. Python is used everywhere โ web development (Django, Flask), data science (NumPy, Pandas), AI/ML (TensorFlow, PyTorch), automation, and more.
1.2 Python 2 vs Python 3
| Feature | Python 2 | Python 3 |
|---|---|---|
print "hello" (statement) | print("hello") (function) | |
| Integer Division | 5/2 = 2 | 5/2 = 2.5 |
| Unicode | ASCII by default | Unicode by default |
| Input | raw_input() | input() |
| Status | End of Life (Jan 2020) | Use this! |
Always Use Python 3
Python 2 reached End of Life on January 1, 2020. All new projects should use Python 3.x. As of 2025, the latest stable version is Python 3.12+.
1.3 Installing Python on Windows
Step-by-Step Installation
- Go to
https://www.python.org/downloads/ - Click "Download Python 3.12.x" (latest stable)
- IMPORTANT: Check โ "Add Python to PATH" on the installer
- Click "Install Now" (default settings are fine)
- Verify: open Command Prompt, type
python --version
Command Prompt
# Verify Python installation
C:\> python --version
Python 3.12.4
# Verify pip (package installer)
C:\> pip --version
pip 24.0 from C:\Python312\Lib\site-packages\pip (python 3.12)
1.4 Your First Python Program
Create a file called hello.py and type:
Python
# hello.py โ Your first Python program!
print("Hello, World!")
Run it from the terminal:
Command Prompt
C:\projects> python hello.py
Hello, World!
1.5 Ways to Run Python
| Method | Best For | How |
|---|---|---|
| IDLE | Quick testing, beginners | Comes with Python, search "IDLE" in Start |
| VS Code | Real projects, debugging | Install Python extension, press F5 to run |
| Command Line | Scripts, automation | python filename.py |
| Interactive Mode | Quick experiments | Type python in terminal โ type code |
| Jupyter Notebook | Data science, learning | pip install jupyter โ jupyter notebook |
1.6 The print() Function
Python
# Basic printing
print("Hello, World!") # String
print(42) # Number
print(3.14) # Float
print(True) # Boolean
# Multiple values
print("Name:", "Alice", "Age:", 25)
# Output: Name: Alice Age: 25
# Custom separator and end
print("A", "B", "C", sep="-") # Output: A-B-C
print("Hello", end=" ") # No newline at end
print("World") # Output: Hello World
# Escape characters
print("Line1\nLine2") # Newline
print("Tab\there") # Tab
print("She said \"hi\"") # Escaped quotes
1.7 The input() Function
Python
# Get user input
name = input("What is your name? ")
print("Hello,", name)
# input() always returns a string!
age_str = input("Enter your age: ") # Returns "25" (a string)
age = int(age_str) # Convert to integer
print("Next year you'll be", age + 1)
# Shortcut: convert inline
num = int(input("Enter a number: "))
print("Double:", num * 2)
Exercises
Exercise 1.1: Write a program that asks for the user's name and age, then prints a greeting
Python
name = input("Enter your name: ")
age = int(input("Enter your age: "))
print(f"Hello {name}! You are {age} years old.")
print(f"In 5 years, you'll be {age + 5}.")
Exercise 1.2: Write a program to calculate the area of a rectangle
Python
length = float(input("Enter length: "))
width = float(input("Enter width: "))
area = length * width
perimeter = 2 * (length + width)
print(f"Area = {area}")
print(f"Perimeter = {perimeter}")
Industry Application: Automated Server Health Check Script
At companies like AWS, Google Cloud, and Azure, DevOps engineers write Python scripts to perform automated server health checks. These scripts run periodically (via cron jobs) to verify system status, Python environment, and uptime โ printing critical diagnostics to monitoring dashboards.
Python
import platform
import sys
import os
from datetime import datetime
# Automated Server Health Check Script
print("โ" * 50)
print("๐ฅ๏ธ SERVER HEALTH CHECK REPORT")
print("โ" * 50)
print(f"Python Version : {sys.version.split()[0]}")
print(f"OS : {platform.system()} {platform.release()}")
print(f"Machine : {platform.machine()}")
print(f"Hostname : {platform.node()}")
print(f"Timestamp : {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print(f"CPU Count : {os.cpu_count()}")
print("โ" * 50)
print("โ
Status: All systems operational")
Quick Quiz โ Chapter 1
Q1. Who created the Python programming language?
- James Gosling
- Guido van Rossum
- Dennis Ritchie
- Bjarne Stroustrup
Q2. What is the correct syntax for printing "Hello" in Python 3?
- echo "Hello"
- print("Hello")
- printf("Hello")
- console.log("Hello")
Q3. What data type does the input() function always return?
- int
- float
- str
- bool
Q4. Python is an _______ language, meaning code is executed line by line.
- compiled
- interpreted
- assembled
- machine-level
Q5. What is the default file extension for Python scripts?
- .pt
- .py
- .python
- .pn
Chapter Summary
- Python 3 is the current standard โ always use Python 3.x
- Always check "Add to PATH" when installing on Windows
print()outputs to the console,input()reads from the userinput()always returns a string โ useint()orfloat()to convert- Use IDLE for quick tests, VS Code for real projects
Variables, Expressions & Statements
Learning Objectives
- Name and use variables following Python conventions
- Understand and avoid NameError
- Differentiate between values, types, and variables
- Know Python's keywords and reserved words
- Distinguish between statements and expressions
2.1 Variables โ Names for Values
A variable is a name that refers to a value stored in memory. Think of it as a label attached to a box, not the box itself.
Python
# Creating variables (no declaration needed!)
message = "Hello, Python!"
age = 21
pi = 3.14159
is_student = True
# Variables can change value AND type (dynamic typing)
x = 10 # x is an integer
x = "ten" # x is now a string (no error!)
x = 10.0 # x is now a float
2.2 Naming Rules & Conventions
| Rule | Valid โ | Invalid โ |
|---|---|---|
| Must start with letter or _ | name, _count | 2name, @value |
| Can contain letters, digits, _ | my_var2 | my-var, my var |
| Case-sensitive | Name โ name โ NAME | โ |
| Cannot be a keyword | my_class | class, for, if |
PEP 8 Naming Conventions
Variables & functions: snake_case (e.g., student_name, total_marks). Constants: UPPER_SNAKE_CASE (e.g., MAX_SIZE, PI). Classes: PascalCase (e.g., StudentRecord). Avoid: single letters (except i, j, k in loops), ambiguous names like l (looks like 1).
2.3 Avoiding NameError
Python
# NameError: using a variable before defining it
print(greeting) # โ NameError: name 'greeting' is not defined
greeting = "Hello"
print(greeting) # โ
Works โ defined before use
# Common mistake: typos
student_name = "Alice"
print(studnet_name) # โ NameError (typo: studnet)
# Fix: Python is case-sensitive
Name = "Alice"
print(name) # โ NameError โ 'name' โ 'Name'
2.4 Values and Types
Every value in Python has a type. Use type() to check:
Python
print(type(42)) # <class 'int'>
print(type(3.14)) # <class 'float'>
print(type("hello")) # <class 'str'>
print(type(True)) # <class 'bool'>
print(type(None)) # <class 'NoneType'>
print(type([1,2,3])) # <class 'list'>
# Type conversion
x = "42"
y = int(x) # String โ Integer: 42
z = float(x) # String โ Float: 42.0
s = str(42) # Integer โ String: "42"
b = bool(0) # Integer โ Boolean: False
b = bool(1) # Integer โ Boolean: True
2.5 Python Keywords
Python
# View all 35 Python keywords
import keyword
print(keyword.kwlist)
# ['False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await',
# 'break', 'class', 'continue', 'def', 'del', 'elif', 'else',
# 'except', 'finally', 'for', 'from', 'global', 'if', 'import',
# 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise',
# 'return', 'try', 'while', 'with', 'yield']
2.6 Statements vs Expressions
An expression produces a value: 3 + 4, x * 2, len("hi"). A statement performs an action: x = 5, print("hi"), if x > 0:.
Python
# Expressions (produce values)
3 + 4 # โ 7
len("hello") # โ 5
x * 2 + 1 # โ depends on x
# Statements (perform actions)
x = 10 # Assignment statement
print(x) # Print statement
import math # Import statement
del x # Delete statement
2.7 Comments
Python
# Single-line comment
x = 42 # Inline comment
# Multi-line comment (use # on each line)
# This is a longer comment
# that spans multiple lines
"""
Docstring โ used for documentation.
Technically a string literal, not a comment.
Used for function/class documentation.
"""
def greet(name):
"""Return a greeting message for the given name."""
return f"Hello, {name}!"
Exercises
Exercise 2.1: What is wrong with each variable name?
2fast โ starts with a digit. my-var โ contains hyphen (use my_var). class โ Python keyword. my var โ contains space. @email โ starts with special character. All fixed: fast2, my_var, my_class, my_var, email.
Exercise 2.2: What does this code output?
Python
x = 5
y = x
x = 10
print(y) # Output: 5 (y still refers to 5, not x)
Answer: 5. When y = x, y gets the value 5. Changing x later doesn't affect y โ integers are immutable, so y keeps its own copy of the value.
Exercise 2.3: Write a program to swap two variables without a temp variable
Python
a = 10
b = 20
print(f"Before: a={a}, b={b}")
a, b = b, a # Python's elegant swap!
print(f"After: a={a}, b={b}")
# Output:
# Before: a=10, b=20
# After: a=20, b=10
Industry Application: E-Commerce Cart Total Calculator
At companies like Amazon, Flipkart, and Shopify, shopping cart systems use variables to track product prices, quantities, tax rates, and discount codes. The backend calculates the final amount dynamically as users add/remove items โ exactly using the variable and expression concepts covered in this chapter.
Python
# E-Commerce Shopping Cart Calculator
# Variables for product details
product_name = "Wireless Headphones"
unit_price = 2499.00
quantity = 2
tax_rate = 0.18 # 18% GST
discount_percent = 10 # 10% festival discount
coupon_flat = 200 # โน200 coupon
# Expressions to calculate total
subtotal = unit_price * quantity
discount_amount = subtotal * (discount_percent / 100)
after_discount = subtotal - discount_amount - coupon_flat
tax_amount = after_discount * tax_rate
final_total = after_discount + tax_amount
# Display invoice
print(f"Product : {product_name}")
print(f"Price : โน{unit_price} ร {quantity} = โน{subtotal}")
print(f"Discount : -โน{discount_amount} (10% off)")
print(f"Coupon : -โน{coupon_flat}")
print(f"Tax (18%): +โน{tax_amount:.2f}")
print(f"โโโโโโโโโโโโโโโโโโโโโโโโโโ")
print(f"Total : โน{final_total:.2f}")
Quick Quiz โ Chapter 2
Q1. Which of the following is a valid Python variable name?
- 2nd_place
- my-variable
- _total_count
- class
Q2. What does "dynamic typing" mean in Python?
- Variables must be declared with a type keyword
- A variable can hold values of different types during execution
- Python converts all values to strings automatically
- Variables cannot change their value once assigned
Q3. What does type(3.14) return?
- <class 'int'>
- <class 'float'>
- <class 'str'>
- <class 'double'>
Q4. What is the PEP 8 recommended naming convention for variables?
- camelCase
- snake_case
- PascalCase
- UPPER_CASE
Q5. How many keywords does Python 3 have (approximately)?
- 15
- 25
- 35
- 50
Chapter Summary
- Variables are names (labels) that refer to values โ no declaration needed
- Follow PEP 8:
snake_casefor variables,UPPER_CASEfor constants - NameError means you used a variable before defining it (or made a typo)
- Python has dynamic typing โ a variable can change type
- Use
type()to check andint(),float(),str()to convert - Expressions produce values; statements perform actions
Operators & String Operations
Learning Objectives
- Use all Python operators: arithmetic, comparison, logical, assignment
- Understand operator precedence (order of operations)
- Perform string operations: concatenation, repetition, slicing
- Use essential string methods
- Understand composition of expressions
3.1 Arithmetic Operators
Python supports all standard mathematical operators. These work with both integers and floats.
| Operator | Name | Example | Result |
|---|---|---|---|
+ | Addition | 7 + 3 | 10 |
- | Subtraction | 7 - 3 | 4 |
* | Multiplication | 7 * 3 | 21 |
/ | Division (float) | 7 / 3 | 2.3333 |
// | Floor Division | 7 // 3 | 2 |
% | Modulus (remainder) | 7 % 3 | 1 |
** | Exponentiation | 7 ** 3 | 343 |
Python
# Arithmetic operators in action
a = 17
b = 5
print("Addition: ", a + b) # 22
print("Subtraction: ", a - b) # 12
print("Multiplication:", a * b) # 85
print("Division: ", a / b) # 3.4
print("Floor Division:", a // b) # 3
print("Modulus: ", a % b) # 2
print("Power: ", a ** b) # 1419857
Division vs Floor Division
/ always returns a float (even 10 / 2 gives 5.0). // returns the largest integer less than or equal to the result. With negative numbers: -7 // 2 gives -4 (not -3), because it rounds down toward negative infinity.
3.2 Comparison Operators
Comparison operators compare two values and return a Boolean (True or False).
| Operator | Meaning | Example | Result |
|---|---|---|---|
== | Equal to | 5 == 5 | True |
!= | Not equal to | 5 != 3 | True |
< | Less than | 3 < 5 | True |
> | Greater than | 3 > 5 | False |
<= | Less than or equal | 5 <= 5 | True |
>= | Greater than or equal | 3 >= 5 | False |
Python
x = 10
y = 20
print(x == y) # False
print(x != y) # True
print(x < y) # True
print(x > y) # False
print(x <= 10) # True
print(x >= 15) # False
# Chained comparisons (Python special!)
age = 25
print(18 <= age <= 30) # True โ is age between 18 and 30?
3.3 Assignment Operators
Assignment operators combine an operation with assignment for cleaner code.
| Operator | Example | Equivalent To |
|---|---|---|
= | x = 5 | Assign 5 to x |
+= | x += 3 | x = x + 3 |
-= | x -= 3 | x = x - 3 |
*= | x *= 3 | x = x * 3 |
/= | x /= 3 | x = x / 3 |
//= | x //= 3 | x = x // 3 |
%= | x %= 3 | x = x % 3 |
**= | x **= 3 | x = x ** 3 |
Python
score = 100
score += 10 # score = 110
score -= 5 # score = 105
score *= 2 # score = 210
score //= 3 # score = 70
print(score) # 70
3.4 Order of Operations (PEMDAS/BODMAS)
Python follows the standard mathematical order of operations. Use parentheses to override when needed.
() โ ** โ +x, -x (unary) โ *, /, //, % โ +, -
PEMDAS: Parentheses, Exponents, Multiplication/Division, Addition/Subtraction
Python
# Order of operations examples
result = 2 + 3 * 4 # 14, not 20 (multiplication first)
result = (2 + 3) * 4 # 20 (parentheses override)
result = 2 ** 3 ** 2 # 512 (** is right-associative: 2^(3^2) = 2^9)
result = 10 - 3 + 2 # 9 (left to right for same precedence)
result = 20 / 4 * 2 # 10.0 (left to right)
result = 2 + 3 * 4 ** 2 # 50 (4**2=16, 3*16=48, 2+48=50)
print(2 + 3 * 4) # 14
print((2 + 3) * 4) # 20
3.5 String Concatenation & Repetition
The + and * operators have special meaning when used with strings.
Python
# String concatenation with +
first = "Hello"
second = "World"
greeting = first + " " + second
print(greeting) # Hello World
# String repetition with *
line = "=" * 30
print(line) # ==============================
banner = "Ha" * 5
print(banner) # HaHaHaHaHa
# Cannot concatenate string + number directly
# print("Age: " + 25) โ TypeError
print("Age: " + str(25)) # โ
Age: 25
3.6 String Indexing & Slicing
Strings are sequences of characters. Each character has an index (position), starting from 0. Negative indices count from the end.
Python
text = "PYTHON"
# P Y T H O N
# 0 1 2 3 4 5 โ positive index
# -6 -5 -4 -3 -2 -1 โ negative index
print(text[0]) # P (first character)
print(text[5]) # N (last character)
print(text[-1]) # N (last character)
print(text[-2]) # O (second from end)
# Slicing: string[start:stop:step]
print(text[0:3]) # PYT (index 0, 1, 2 โ stop is excluded)
print(text[2:5]) # THO
print(text[:3]) # PYT (start defaults to 0)
print(text[3:]) # HON (stop defaults to end)
print(text[:]) # PYTHON (full copy)
print(text[::-1]) # NOHTYP (reversed!)
print(text[0:6:2]) # PTO (every 2nd character)
3.7 Essential String Methods
Strings have many built-in methods. Since strings are immutable, these methods return new strings.
Case Methods
Python
text = "Hello, World!"
print(text.upper()) # HELLO, WORLD!
print(text.lower()) # hello, world!
print(text.title()) # Hello, World!
print(text.capitalize()) # Hello, world!
print(text.swapcase()) # hELLO, wORLD!
Search & Replace Methods
Python
text = "Python is awesome and Python is fun"
print(text.find("Python")) # 0 (first occurrence index)
print(text.find("Python", 5)) # 22 (search from index 5)
print(text.find("Java")) # -1 (not found)
print(text.count("Python")) # 2
print(text.replace("Python", "Java"))
# Java is awesome and Java is fun
print(text.startswith("Python")) # True
print(text.endswith("fun")) # True
Strip, Split & Join
Python
# strip() โ remove whitespace from both ends
messy = " Hello World "
print(messy.strip()) # "Hello World"
print(messy.lstrip()) # "Hello World "
print(messy.rstrip()) # " Hello World"
# split() โ break string into a list
sentence = "Python is great"
words = sentence.split()
print(words) # ['Python', 'is', 'great']
csv_data = "apple,banana,cherry"
fruits = csv_data.split(",")
print(fruits) # ['apple', 'banana', 'cherry']
# join() โ combine a list into a string
words = ["Python", "is", "fun"]
result = " ".join(words)
print(result) # Python is fun
path = "/".join(["home", "user", "docs"])
print(path) # home/user/docs
3.8 Composition of Expressions
Composition means combining simple expressions to build complex ones. You can use expressions anywhere a value is expected.
Python
# Composing expressions
x = 10
y = 3
# Nesting function calls
result = str(round(abs(x / y), 2))
print(result) # "3.33"
# Combining string methods
name = " john DOE "
clean_name = name.strip().title()
print(clean_name) # John Doe
# Using expressions in f-strings
radius = 5
print(f"Area = {3.14159 * radius ** 2:.2f}") # Area = 78.54
# Expression as argument
print("Average:", (85 + 92 + 78) / 3) # Average: 85.0
Exercises
Exercise 3.1: Write a program that takes two numbers and prints all arithmetic operations
Python
a = float(input("Enter first number: "))
b = float(input("Enter second number: "))
print(f"{a} + {b} = {a + b}")
print(f"{a} - {b} = {a - b}")
print(f"{a} * {b} = {a * b}")
print(f"{a} / {b} = {a / b}")
print(f"{a} // {b} = {a // b}")
print(f"{a} % {b} = {a % b}")
print(f"{a} ** {b} = {a ** b}")
Exercise 3.2: Write a program that reverses a string and checks if it's a palindrome
Python
text = input("Enter a string: ").lower().strip()
reversed_text = text[::-1]
print(f"Original: {text}")
print(f"Reversed: {reversed_text}")
if text == reversed_text:
print("It's a palindrome! โ
")
else:
print("Not a palindrome โ")
Exercise 3.3: Clean and format a messy user input string
Python
# Given messy input, clean and format it
raw = " jOhN dOe "
# Step 1: Strip whitespace
cleaned = raw.strip()
# Step 2: Normalize spaces (split and rejoin)
words = cleaned.split()
cleaned = " ".join(words)
# Step 3: Title case
formatted = cleaned.title()
print(f"Raw: '{raw}'")
print(f"Formatted: '{formatted}'")
print(f"Length: {len(formatted)}")
print(f"Initials: {formatted.split()[0][0]}.{formatted.split()[1][0]}.")
Industry Application: Banking EMI Calculator & Customer Name Normalization
Banks like HDFC, SBI, and ICICI use Python scripts for loan EMI calculations using arithmetic operators. The standard EMI formula uses exponentiation, division, and multiplication. Additionally, CRM systems normalize customer names using string methods to ensure consistent data across databases.
Python
# Part 1: EMI Calculator (used in banking systems)
principal = 500000 # Loan amount โน5,00,000
annual_rate = 8.5 # 8.5% annual interest
tenure_years = 5 # 5 years
# EMI Formula: P ร r ร (1+r)^n / ((1+r)^n - 1)
r = annual_rate / (12 * 100) # Monthly interest rate
n = tenure_years * 12 # Total months
emi = principal * r * (1 + r) ** n / ((1 + r) ** n - 1)
print("โโโ LOAN EMI CALCULATOR โโโ")
print(f"Loan Amount : โน{principal:,}")
print(f"Interest Rate: {annual_rate}% per annum")
print(f"Tenure : {tenure_years} years ({n} months)")
print(f"Monthly EMI : โน{emi:,.2f}")
print(f"Total Payment: โน{emi * n:,.2f}")
print(f"Total Interest: โน{(emi * n) - principal:,.2f}")
# Part 2: Customer Name Normalization (CRM System)
print("\nโโโ CUSTOMER NAME NORMALIZATION โโโ")
raw_names = [" john DOE ", "JANE smith", " bob WILSON "]
for name in raw_names:
clean = name.strip().title()
parts = clean.split()
normalized = " ".join(parts)
print(f"'{name}' โ '{normalized}'")
Quick Quiz โ Chapter 3
Q1. What is the result of 17 // 5 in Python?
- 3.4
- 3
- 4
- 2
Q2. What is the output of 2 + 3 * 4 ** 2?
- 80
- 50
- 200
- 36
Q3. Strings in Python are:
- Mutable โ can be changed in place
- Immutable โ cannot be changed after creation
- Only mutable when using single quotes
- Stored as integers internally
Q4. What does "PYTHON"[1:4] return?
- "PYT"
- "YTH"
- "YTHO"
- "PYTH"
Q5. What is the output of " Hello ".strip().upper()?
- " HELLO "
- "HELLO"
- "Hello"
- "hello"
Chapter Summary
- Arithmetic operators:
+,-,*,/(float),//(floor),%(modulus),**(power) - Comparison operators return
True/False:==,!=,<,>,<=,>= - Assignment operators:
+=,-=,*=, etc. combine operation with assignment - Operator precedence follows PEMDAS โ use parentheses when in doubt
- Strings support
+(concatenation) and*(repetition) - String indexing starts at 0; negative indices count from the end
- Slicing:
str[start:stop:step]extracts substrings - Key string methods:
upper(),lower(),strip(),split(),join(),replace(),find()
Control Flow
Conditional and iterative statements
Conditional Statements
Learning Objectives
- Use the modulus operator for divisibility checks
- Generate random numbers
- Write Boolean expressions with logical operators
- Implement if, if-else, if-elif-else chains
- Build nested conditional structures
4.1 The Modulus Operator (%)
The modulus operator returns the remainder of division. It's incredibly useful for divisibility checks, cycling through values, and extracting digits.
Python
# Basic modulus usage
print(17 % 5) # 2 (17 = 5*3 + 2)
print(20 % 4) # 0 (perfectly divisible)
print(7 % 2) # 1 (odd number)
print(8 % 2) # 0 (even number)
# Practical uses
num = 42
if num % 2 == 0:
print(f"{num} is even")
else:
print(f"{num} is odd")
# Extract last digit
number = 12345
last_digit = number % 10
print(f"Last digit of {number}: {last_digit}") # 5
# Check divisibility
print(15 % 3 == 0) # True โ 15 is divisible by 3
print(15 % 4 == 0) # False โ 15 is NOT divisible by 4
4.2 Random Numbers
The random module provides functions for generating random numbers โ essential for games, simulations, and testing.
Python
import random
# randint(a, b) โ random integer from a to b (inclusive)
dice = random.randint(1, 6)
print(f"Dice roll: {dice}") # e.g., 4
# random() โ random float between 0.0 and 1.0
prob = random.random()
print(f"Probability: {prob:.4f}") # e.g., 0.7341
# choice() โ pick a random element from a sequence
colors = ["red", "blue", "green", "yellow"]
pick = random.choice(colors)
print(f"Random color: {pick}") # e.g., blue
# randrange(start, stop, step) โ like range() but random
even = random.randrange(0, 100, 2)
print(f"Random even: {even}") # e.g., 46
4.3 Boolean Expressions & Truthiness
A Boolean expression evaluates to either True or False. Python has a concept of truthiness โ some values are considered "truthy" and others "falsy".
| Falsy Values (evaluate to False) | Truthy Values (evaluate to True) |
|---|---|
False, None, 0, 0.0 | True, any non-zero number |
"" (empty string) | Any non-empty string |
[], (), {} (empty collections) | Any non-empty collection |
Python
# Truthiness examples
print(bool(0)) # False
print(bool(42)) # True
print(bool("")) # False
print(bool("hello")) # True
print(bool([])) # False
print(bool([1,2])) # True
# Practical use of truthiness
name = input("Enter your name: ")
if name: # truthy if not empty
print(f"Hello, {name}!")
else:
print("You didn't enter a name!")
4.4 Logical Operators: and, or, not
Logical operators combine Boolean expressions.
| A | B | A and B | A or B | not A |
|---|---|---|---|---|
| True | True | True | True | False |
| True | False | False | True | False |
| False | True | False | True | True |
| False | False | False | False | True |
Python
age = 25
has_license = True
# and โ both must be True
can_drive = age >= 18 and has_license
print(f"Can drive: {can_drive}") # True
# or โ at least one must be True
is_weekend = False
is_holiday = True
day_off = is_weekend or is_holiday
print(f"Day off: {day_off}") # True
# not โ reverses the boolean
is_raining = False
go_outside = not is_raining
print(f"Go outside: {go_outside}") # True
# Combined example
score = 85
attendance = 90
passed = score >= 50 and attendance >= 75
print(f"Passed: {passed}") # True
4.5 if Statement
Python
# Simple if
temperature = 35
if temperature > 30:
print("It's hot outside! ๐ฅ")
print("Stay hydrated!")
# if-else
age = int(input("Enter your age: "))
if age >= 18:
print("You are an adult โ
")
else:
print("You are a minor โ")
4.6 if-elif-else Chains
Python
# Grade calculator
marks = int(input("Enter marks (0-100): "))
if marks >= 90:
grade = "A+"
elif marks >= 80:
grade = "A"
elif marks >= 70:
grade = "B"
elif marks >= 60:
grade = "C"
elif marks >= 50:
grade = "D"
else:
grade = "F (Fail)"
print(f"Marks: {marks} โ Grade: {grade}")
4.7 Nested Conditionals
Python
# Nested if โ Ticket pricing system
age = int(input("Enter age: "))
is_student = input("Are you a student? (yes/no): ").lower()
if age < 12:
price = 0
category = "Child (Free)"
elif age < 18:
price = 50
category = "Teen"
elif age < 60:
if is_student == "yes":
price = 75
category = "Student (discounted)"
else:
price = 100
category = "Adult"
else:
price = 60
category = "Senior Citizen"
print(f"Category: {category}")
print(f"Ticket Price: โน{price}")
4.8 Ternary Operator (Conditional Expression)
Python's ternary operator provides a one-line if-else:
Python
age = 20
status = "Adult" if age >= 18 else "Minor"
print(status) # Adult
# Finding the maximum of two numbers
a, b = 15, 22
maximum = a if a > b else b
print(f"Max: {maximum}") # Max: 22
# Even/Odd check
num = 7
result = "Even" if num % 2 == 0 else "Odd"
print(f"{num} is {result}") # 7 is Odd
# Absolute value (manual)
x = -10
abs_val = x if x >= 0 else -x
print(f"Absolute: {abs_val}") # Absolute: 10
Exercises
Exercise 4.1: Write a program to check if a year is a leap year
Python
year = int(input("Enter a year: "))
if (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0):
print(f"{year} is a leap year โ
")
else:
print(f"{year} is not a leap year โ")
Exercise 4.2: Build a simple calculator with +, -, *, /
Python
a = float(input("Enter first number: "))
op = input("Enter operator (+, -, *, /): ")
b = float(input("Enter second number: "))
if op == "+":
result = a + b
elif op == "-":
result = a - b
elif op == "*":
result = a * b
elif op == "/":
if b != 0:
result = a / b
else:
result = "Error: Division by zero!"
else:
result = "Invalid operator!"
print(f"Result: {a} {op} {b} = {result}")
Exercise 4.3: Write a number guessing game using random
Python
import random
secret = random.randint(1, 10)
guess = int(input("Guess a number (1-10): "))
if guess == secret:
print("๐ Correct! You win!")
elif abs(guess - secret) <= 2:
print(f"Close! The number was {secret}")
else:
print(f"Wrong! The number was {secret}")
Industry Application: Credit Score-Based Loan Eligibility Checker
Fintech companies like CRED, Paytm, and BankBazaar use CIBIL credit score ranges combined with income criteria to determine loan eligibility in real-time. This conditional logic powers the instant loan approval/rejection systems you see in banking apps.
Python
# Credit Score-Based Loan Eligibility Checker
# Used by banks and fintech companies for instant decisions
applicant = "Priya Sharma"
cibil_score = 745
annual_income = 850000 # โน8.5 Lakhs
existing_loans = 1
loan_amount = 500000 # Requested: โน5 Lakhs
print("โโโ LOAN ELIGIBILITY REPORT โโโ")
print(f"Applicant : {applicant}")
print(f"CIBIL Score : {cibil_score}")
print(f"Annual Income: โน{annual_income:,}")
if cibil_score >= 750 and annual_income >= 500000:
interest_rate = 8.5
status = "โ
APPROVED โ Excellent Score"
max_loan = annual_income * 5
elif cibil_score >= 650 and annual_income >= 400000:
interest_rate = 11.5
status = "โ
APPROVED โ Good Score"
max_loan = annual_income * 3
elif cibil_score >= 550:
interest_rate = 16.0
status = "โ ๏ธ CONDITIONAL โ Average Score"
max_loan = annual_income * 1.5
else:
interest_rate = 0
status = "โ REJECTED โ Poor Score (below 550)"
max_loan = 0
print(f"Status : {status}")
if max_loan > 0:
print(f"Max Eligible : โน{max_loan:,.0f}")
print(f"Interest Rate: {interest_rate}%")
if loan_amount <= max_loan:
print(f"Requested โน{loan_amount:,} โ โ
Within limit")
else:
print(f"Requested โน{loan_amount:,} โ โ Exceeds limit")
Quick Quiz โ Chapter 4
Q1. Which of the following is NOT a valid Boolean value in Python?
- True
- False
- true
- None is not a Boolean but is valid Python
Q2. What is the difference between elif and else?
- They are identical in behavior
- elif checks a new condition; else runs when all previous conditions are False
- else can have a condition; elif cannot
- elif is not a valid Python keyword
Q3. What is the correct syntax for Python's ternary (conditional) expression?
- condition ? value_if_true : value_if_false
- value_if_true if condition else value_if_false
- if condition then value_if_true else value_if_false
- condition && value_if_true || value_if_false
Q4. In nested if statements, how does Python determine which block a statement belongs to?
- By using curly braces {}
- By using begin/end keywords
- By indentation level
- By the order of statements
Q5. Which of the following values is considered "truthy" in Python?
- 0
- ""
- "False"
- None
Chapter Summary
%(modulus) returns the remainder โ use for even/odd and divisibility checks- The
randommodule providesrandint(),random(),choice(),randrange() - Falsy values:
0,"",None,[],Falseโ everything else is truthy - Logical operators:
and(both true),or(at least one),not(reverse) if-elif-elsechains handle multiple conditions โ only the first true branch runs- Nested conditionals allow deeper decision trees
- Ternary:
value = x if condition else yfor one-line decisions
Iterative Statements (Loops)
Learning Objectives
- Master while loops: counters, sentinels, infinite loops
- Use for loops with range() and sequences
- Build nested loops for patterns and matrices
- Control flow with break, continue, pass
- Understand encapsulation and generalization
5.1 The while Loop
A while loop repeats a block of code as long as a condition is True. Be careful โ if the condition never becomes False, you get an infinite loop!
Python
# Counter pattern โ most common while loop
count = 1
while count <= 5:
print(f"Count: {count}")
count += 1 # Don't forget to update!
Python
# Sentinel loop โ stops on a special value
total = 0
print("Enter numbers to add (type 0 to stop):")
while True:
num = int(input("Number: "))
if num == 0:
break
total += num
print(f"Total: {total}")
# Countdown
n = 5
while n > 0:
print(n, end=" ")
n -= 1
print("Blast off! ๐")
# Output: 5 4 3 2 1 Blast off! ๐
5.2 The for Loop & range()
The for loop iterates over a sequence. range() generates number sequences.
Python
# range(stop) โ 0 to stop-1
for i in range(5):
print(i, end=" ") # 0 1 2 3 4
print()
# range(start, stop) โ start to stop-1
for i in range(1, 6):
print(i, end=" ") # 1 2 3 4 5
print()
# range(start, stop, step)
for i in range(0, 20, 3):
print(i, end=" ") # 0 3 6 9 12 15 18
print()
# Counting backwards
for i in range(10, 0, -1):
print(i, end=" ") # 10 9 8 7 6 5 4 3 2 1
print()
5.3 Iterating Over Strings & Lists
Python
# Iterate over a string
for char in "PYTHON":
print(char, end="-") # P-Y-T-H-O-N-
print()
# Iterate over a list
fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
print(f"I like {fruit}")
# Using enumerate() for index + value
for i, fruit in enumerate(fruits):
print(f"{i}: {fruit}")
# 0: apple
# 1: banana
# 2: cherry
5.4 Nested Loops
A loop inside another loop. The inner loop completes all its iterations for each iteration of the outer loop.
Python
# Multiplication table (1 to 5)
for i in range(1, 6):
for j in range(1, 6):
print(f"{i*j:4}", end="")
print() # new line after each row
Python
# Right triangle star pattern
n = 5
for i in range(1, n + 1):
print("* " * i)
Python
# Pyramid pattern
n = 5
for i in range(1, n + 1):
spaces = " " * (n - i)
stars = "* " * i
print(spaces + stars)
5.5 break, continue, pass
| Statement | Purpose |
|---|---|
break | Exit the loop entirely |
continue | Skip current iteration, go to next |
pass | Do nothing (placeholder) |
Python
# break โ exit when found
for num in range(1, 100):
if num % 7 == 0 and num % 5 == 0:
print(f"First number divisible by 7 and 5: {num}")
break
# Output: First number divisible by 7 and 5: 35
# continue โ skip odd numbers
print("Even numbers:", end=" ")
for i in range(1, 11):
if i % 2 != 0:
continue
print(i, end=" ")
# Output: Even numbers: 2 4 6 8 10
# pass โ placeholder for future code
for i in range(5):
if i == 3:
pass # TODO: handle this case later
print(i, end=" ")
# Output: 0 1 2 3 4 (pass does nothing)
5.6 for-else and while-else
Python's unique else clause on loops runs only if the loop completed without hitting a break.
Python
# Check if a number is prime
num = 17
for i in range(2, num):
if num % i == 0:
print(f"{num} is NOT prime (divisible by {i})")
break
else:
print(f"{num} IS prime โ
")
# Output: 17 IS prime โ
5.7 Random Numbers in Loops
Python
import random
# Dice rolling simulation
rolls = 0
while True:
dice = random.randint(1, 6)
rolls += 1
print(f"Roll {rolls}: {dice}")
if dice == 6:
print(f"Got a 6 after {rolls} rolls! ๐ฒ")
break
5.8 Encapsulation & Generalization
Encapsulation means wrapping a piece of code in a function. Generalization means replacing specific values with parameters to make the function more flexible.
Python
# Before: specific code
for i in range(1, 6):
print("* " * i)
# After encapsulation: wrap in a function
def print_triangle():
for i in range(1, 6):
print("* " * i)
# After generalization: make size a parameter
def print_triangle(n, char="*"):
"""Print a right triangle of height n using char."""
for i in range(1, n + 1):
print((char + " ") * i)
print_triangle(4) # default * character
print_triangle(3, "#") # custom # character
Exercises
Exercise 5.1: Print the sum of all even numbers from 1 to 100
Python
# Method 1: for loop
total = 0
for i in range(2, 101, 2):
total += i
print(f"Sum of even numbers (1-100): {total}")
# Method 2: formula
print(f"Using formula: {sum(range(2, 101, 2))}")
Exercise 5.2: Print a number pyramid pattern
Python
n = 5
for i in range(1, n + 1):
# Print leading spaces
print(" " * (n - i), end="")
# Print numbers
for j in range(1, i + 1):
print(j, end=" ")
print()
Exercise 5.3: Write a guessing game with while loop (multiple attempts)
Python
import random
secret = random.randint(1, 50)
attempts = 0
max_attempts = 7
print("๐ฏ Guess the number (1-50)!")
print(f"You have {max_attempts} attempts.")
while attempts < max_attempts:
guess = int(input("Your guess: "))
attempts += 1
if guess == secret:
print(f"๐ Correct in {attempts} attempts!")
break
elif guess < secret:
print("Too low! โฌ๏ธ")
else:
print("Too high! โฌ๏ธ")
remaining = max_attempts - attempts
print(f"Attempts remaining: {remaining}")
else:
print(f"๐ Game Over! The number was {secret}")
Industry Application: Server Log Analysis โ HTTP Status Code Counter
At companies like Netflix, Google, and Cloudflare, SRE (Site Reliability Engineering) teams analyze server logs to monitor uptime and detect issues. Python scripts loop through log entries, counting HTTP status codes (200 OK, 404 Not Found, 500 Internal Server Error) to generate health reports and trigger alerts.
Python
# Server Log Analyzer โ Count HTTP Status Codes
# Simulates real log analysis at tech companies
server_logs = [
"2025-06-15 10:23:01 GET /home 200",
"2025-06-15 10:23:05 GET /api/users 200",
"2025-06-15 10:23:12 POST /login 200",
"2025-06-15 10:23:18 GET /dashboard 404",
"2025-06-15 10:23:25 GET /api/data 500",
"2025-06-15 10:23:30 GET /home 200",
"2025-06-15 10:23:35 DELETE /api/old 404",
"2025-06-15 10:23:42 POST /api/save 500",
"2025-06-15 10:23:50 GET /about 200",
"2025-06-15 10:23:55 GET /contact 200",
]
# Count status codes using a loop
status_counts = {"200": 0, "404": 0, "500": 0, "other": 0}
for i, log in enumerate(server_logs, 1):
status_code = log.split()[-1] # Last word is the status
if status_code in status_counts:
status_counts[status_code] += 1
else:
status_counts["other"] += 1
# Generate report
total = len(server_logs)
print("โโโ SERVER LOG ANALYSIS REPORT โโโ")
print(f"Total Requests: {total}")
print(f"โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ")
for code, count in status_counts.items():
pct = (count / total) * 100
bar = "โ" * int(pct / 5)
if count > 0:
print(f" {code}: {count:3d} ({pct:5.1f}%) {bar}")
# Alert check
error_rate = (status_counts["500"] / total) * 100
if error_rate > 10:
print("๐จ ALERT: Error rate exceeds 10%!")
else:
print("โ
Server health: Normal")
Quick Quiz โ Chapter 5
Q1. What does range(2, 10, 3) produce?
- [2, 5, 8]
- [2, 5, 8, 11]
- [2, 4, 6, 8]
- [3, 6, 9]
Q2. What is the difference between break and continue?
- They are identical in behavior
- break exits the loop entirely; continue skips to the next iteration
- continue exits the loop; break skips the iteration
- Both are only valid in while loops
Q3. Which of the following creates an infinite loop?
- for i in range(10):
- while True:
- while False:
- for i in []:
Q4. When does the else block of a for-else loop execute?
- When the loop encounters an error
- When the loop condition is False initially
- When the loop completes without hitting a break statement
- After every iteration of the loop
Q5. What does enumerate(["a", "b", "c"]) produce?
- ["a", "b", "c"]
- [(0, "a"), (1, "b"), (2, "c")]
- [1, 2, 3]
- {"a": 0, "b": 1, "c": 2}
Chapter Summary
whileloops repeat while a condition is True โ always update the condition variableforloops iterate over sequences;range(start, stop, step)generates number sequences- Use
enumerate()to get both index and value while iterating - Nested loops: inner loop fully executes for each outer loop iteration
breakexits the loop,continueskips to next iteration,passdoes nothingfor-else/while-else: the else block runs only if nobreakoccurred- Encapsulation wraps code in functions; generalization adds parameters for flexibility
Functions
Modular programming & recursion
Functions & Recursion
Learning Objectives
- Call built-in functions and understand type conversion
- Import and use the math module
- Define your own functions with parameters and return values
- Understand variable scope (local vs global)
- Implement recursive solutions for classic problems
6.1 Built-in Functions
Python comes with many built-in functions that you can use without importing anything.
Python
# Common built-in functions
numbers = [4, 2, 9, 1, 7, 5]
print(len(numbers)) # 6 (length)
print(max(numbers)) # 9 (maximum)
print(min(numbers)) # 1 (minimum)
print(sum(numbers)) # 28 (total)
print(sorted(numbers)) # [1, 2, 4, 5, 7, 9]
print(abs(-42)) # 42 (absolute value)
print(round(3.14159, 2)) # 3.14 (round to 2 decimals)
print(pow(2, 10)) # 1024 (2^10)
6.2 Type Conversion Functions
Python
# Type conversion (casting)
print(int("42")) # 42 (string โ int)
print(int(3.99)) # 3 (truncates, not rounds!)
print(float("3.14")) # 3.14 (string โ float)
print(float(42)) # 42.0 (int โ float)
print(str(42)) # "42" (int โ string)
print(str(3.14)) # "3.14" (float โ string)
print(bool(0)) # False
print(bool(1)) # True
print(list("hello")) # ['h', 'e', 'l', 'l', 'o']
print(tuple([1,2,3])) # (1, 2, 3)
Type Coercion Rules
Python automatically converts types in mixed expressions: int + float โ float (e.g., 5 + 2.0 = 7.0). bool is a subclass of int: True + True = 2, True + 5 = 6. String to number conversion must be explicit โ "5" + 3 is a TypeError.
6.3 The math Module
Python
import math
print(math.pi) # 3.141592653589793
print(math.e) # 2.718281828459045
print(math.sqrt(16)) # 4.0
print(math.ceil(3.2)) # 4 (round up)
print(math.floor(3.8)) # 3 (round down)
print(math.pow(2, 10)) # 1024.0
print(math.factorial(5)) # 120 (5! = 5ร4ร3ร2ร1)
print(math.log(100, 10)) # 2.0 (log base 10)
print(math.log2(8)) # 3.0 (log base 2)
print(math.gcd(12, 8)) # 4 (greatest common divisor)
# Practical example
radius = 7
area = math.pi * radius ** 2
print(f"Circle area: {area:.2f}") # 153.94
6.4 Defining Functions
Python
# Basic function definition
def greet(name):
"""Return a greeting message."""
return f"Hello, {name}! Welcome!"
# Call the function
message = greet("Alice")
print(message) # Hello, Alice! Welcome!
# Function with no return (returns None)
def print_separator(char="-", width=40):
"""Print a separator line."""
print(char * width)
print_separator() # ----------------------------------------
print_separator("=", 30) # ==============================
# Function with multiple return values
def min_max(numbers):
"""Return both minimum and maximum."""
return min(numbers), max(numbers)
lo, hi = min_max([3, 7, 1, 9, 2])
print(f"Min: {lo}, Max: {hi}") # Min: 1, Max: 9
6.5 Parameters & Arguments
Python
# Positional arguments โ order matters
def power(base, exponent):
return base ** exponent
print(power(2, 3)) # 8 (2^3)
print(power(3, 2)) # 9 (3^2) โ order matters!
# Keyword arguments โ order doesn't matter
print(power(exponent=3, base=2)) # 8
# Default arguments
def greet(name, greeting="Hello"):
return f"{greeting}, {name}!"
print(greet("Bob")) # Hello, Bob!
print(greet("Bob", "Good morning")) # Good morning, Bob!
# *args โ variable number of positional arguments
def average(*args):
"""Calculate average of any number of values."""
return sum(args) / len(args)
print(average(10, 20, 30)) # 20.0
print(average(5, 10, 15, 20)) # 12.5
# **kwargs โ variable number of keyword arguments
def build_profile(**kwargs):
for key, value in kwargs.items():
print(f" {key}: {value}")
build_profile(name="Alice", age=25, city="Delhi")
6.6 Variable Scope (LEGB Rule)
Python looks up variables in this order: Local โ Enclosing โ Global โ Built-in.
Python
x = "global" # Global scope
def outer():
x = "enclosing" # Enclosing scope
def inner():
x = "local" # Local scope
print("Inner:", x) # local
inner()
print("Outer:", x) # enclosing
outer()
print("Global:", x) # global
# Using 'global' keyword to modify global variable
counter = 0
def increment():
global counter
counter += 1
increment()
increment()
print(counter) # 2
6.7 Recursion
A recursive function calls itself. Every recursive function needs a base case (stopping condition) and a recursive case.
Python
# Factorial: n! = n ร (n-1) ร ... ร 1
def factorial(n):
"""Calculate n! recursively."""
if n <= 1: # Base case
return 1
return n * factorial(n - 1) # Recursive case
print(factorial(5)) # 120 (5 ร 4 ร 3 ร 2 ร 1)
# Fibonacci: F(n) = F(n-1) + F(n-2)
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
for i in range(10):
print(fibonacci(i), end=" ")
# 0 1 1 2 3 5 8 13 21 34
# Sum of digits
def sum_digits(n):
if n < 10:
return n
return n % 10 + sum_digits(n // 10)
print(sum_digits(12345)) # 15 (1+2+3+4+5)
# Power function
def power(base, exp):
if exp == 0:
return 1
return base * power(base, exp - 1)
print(power(2, 10)) # 1024
6.8 Recursion vs Iteration
| Feature | Recursion | Iteration |
|---|---|---|
| Approach | Calls itself | Uses loops |
| Memory | Uses stack (more memory) | Less memory |
| Speed | Slower (function call overhead) | Faster |
| Readability | Elegant for tree/divide problems | Simpler for linear tasks |
| Risk | Stack overflow if too deep | Infinite loop if no exit |
Python
# Factorial โ iterative version for comparison
def factorial_iter(n):
result = 1
for i in range(2, n + 1):
result *= i
return result
print(factorial_iter(5)) # 120 โ same result, faster
Exercises
Exercise 6.1: Write a function that checks if a number is prime
Python
def is_prime(n):
"""Return True if n is prime, False otherwise."""
if n < 2:
return False
for i in range(2, int(n ** 0.5) + 1):
if n % i == 0:
return False
return True
# Test
for num in range(2, 20):
if is_prime(num):
print(num, end=" ")
# Output: 2 3 5 7 11 13 17 19
Exercise 6.2: Write a recursive function for Tower of Hanoi
Python
def hanoi(n, source="A", target="C", auxiliary="B"):
"""Solve Tower of Hanoi for n disks."""
if n == 1:
print(f"Move disk 1 from {source} to {target}")
return
hanoi(n - 1, source, auxiliary, target)
print(f"Move disk {n} from {source} to {target}")
hanoi(n - 1, auxiliary, target, source)
hanoi(3)
Exercise 6.3: Write a function that takes *args and returns statistics
Python
def statistics(*args):
"""Return count, sum, average, min, max."""
n = len(args)
total = sum(args)
avg = total / n
return {
"count": n,
"sum": total,
"average": round(avg, 2),
"min": min(args),
"max": max(args)
}
result = statistics(85, 92, 78, 96, 88)
for key, value in result.items():
print(f" {key}: {value}")
Industry Application: API Rate Limiter with Decorator Pattern
Companies like Twitter/X, Stripe, and GitHub implement rate limiting on their APIs to prevent abuse. Python decorators (which wrap functions) are the standard pattern for this. The decorator tracks how many times an API endpoint is called per minute and blocks excess requests โ a real-world application of functions, closures, and decorators.
Python
import time
from functools import wraps
def rate_limiter(max_calls, period=60):
"""Decorator to limit function calls per time period"""
calls = [] # Closure variable โ tracks timestamps
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
now = time.time()
# Remove calls outside the time window
while calls and calls[0] < now - period:
calls.pop(0)
if len(calls) >= max_calls:
wait = round(period - (now - calls[0]), 1)
print(f"โ Rate limit exceeded! Retry in {wait}s")
return None
calls.append(now)
print(f"โ
Call {len(calls)}/{max_calls} โ {func.__name__}()")
return func(*args, **kwargs)
return wrapper
return decorator
# Usage: Max 3 calls per 60 seconds
@rate_limiter(max_calls=3, period=60)
def get_user_data(user_id):
return {"id": user_id, "name": f"User_{user_id}"}
# Simulate API calls
for i in range(1, 6):
result = get_user_data(i)
if result:
print(f" Data: {result}")
Quick Quiz โ Chapter 6
Q1. What is the difference between *args and **kwargs?
- *args is for strings; **kwargs is for numbers
- *args collects positional arguments as a tuple; **kwargs collects keyword arguments as a dictionary
- They are interchangeable
- *args is for lists; **kwargs is for dictionaries
Q2. What happens if a function does not have a return statement?
- It raises a SyntaxError
- It returns 0
- It returns None
- It returns an empty string
Q3. In the LEGB scope rule, what does the "E" stand for?
- External
- Enclosing
- Environment
- Exported
Q4. What is the essential requirement for a recursive function to work correctly?
- It must use a for loop internally
- It must have a base case that stops the recursion
- It must use global variables
- It must return a string
Q5. What is the output of (lambda x, y: x + y)(3, 4)?
- "34"
- 7
- (3, 4)
- Error
Chapter Summary
- Built-in functions:
len(),max(),min(),sum(),abs(),round(),sorted() - Type conversion:
int(),float(),str(),bool(),list(),tuple() import mathprovidessqrt,ceil,floor,factorial,pi,e,log- Functions:
def name(params): ... return value *argscollects extra positional arguments;**kwargscollects keyword arguments- LEGB scope rule: Local โ Enclosing โ Global โ Built-in
- Recursion needs a base case + recursive case โ elegant for factorial, fibonacci, Hanoi
- Iteration is generally faster; recursion is more elegant for divide-and-conquer
Data Structures
Strings, lists, tuples & dictionaries
Strings
Learning Objectives
- Understand strings as compound data types
- Traverse, slice, and compare strings
- Use find(), count(), and string methods
- Format strings with f-strings
- Understand string immutability
7.1 Strings as Sequences
A string is an ordered sequence of characters. Each character has an index, and you can access individual characters or subsequences using indexing and slicing.
Python
text = "Hello, Python!"
# Length of a string
print(len(text)) # 14
# Accessing characters
print(text[0]) # H (first character)
print(text[-1]) # ! (last character)
print(text[7]) # P
# Membership testing
print("Python" in text) # True
print("Java" not in text) # True
7.2 String Traversal
Python
word = "Python"
# Method 1: for loop (preferred)
for char in word:
print(char, end=" ") # P y t h o n
print()
# Method 2: while loop with index
i = 0
while i < len(word):
print(word[i], end=" ")
i += 1
print()
# Method 3: for loop with index
for i in range(len(word)):
print(f"Index {i}: {word[i]}")
7.3 String Slicing (Deep Dive)
Python
s = "ABCDEFGHIJ"
# 0123456789
print(s[2:7]) # CDEFG
print(s[:5]) # ABCDE (first 5 chars)
print(s[5:]) # FGHIJ (from index 5 to end)
print(s[::-1]) # JIHGFEDCBA (reverse)
print(s[0:10:2]) # ACEGI (every 2nd character)
print(s[-3:]) # HIJ (last 3 characters)
print(s[1:-1]) # BCDEFGHI (remove first and last)
# Reversing a string
original = "racecar"
reversed_str = original[::-1]
print(f"'{original}' reversed = '{reversed_str}'")
print(f"Is palindrome: {original == reversed_str}") # True
7.4 String Comparison
Strings are compared lexicographically (character by character using Unicode values).
Python
print("apple" < "banana") # True (a < b)
print("abc" < "abd") # True (c < d at position 2)
print("abc" < "abcd") # True (shorter string is "less")
print("Zulu" < "alpha") # True (uppercase < lowercase)
# Get Unicode value
print(ord("A")) # 65
print(ord("a")) # 97
print(ord("0")) # 48
print(chr(65)) # A (number โ character)
7.5 find() vs index()
Python
text = "Python programming is fun"
# find() โ returns -1 if not found (safe)
print(text.find("gram")) # 11
print(text.find("Java")) # -1 (not found)
# index() โ raises ValueError if not found (risky)
print(text.index("gram")) # 11
# text.index("Java") # โ ValueError!
# rfind() โ search from the right
text2 = "abcabcabc"
print(text2.find("abc")) # 0 (first occurrence)
print(text2.rfind("abc")) # 6 (last occurrence)
7.6 Looping & Counting Characters
Python
# Count vowels in a string
text = "Hello World"
vowels = "aeiouAEIOU"
count = 0
for char in text:
if char in vowels:
count += 1
print(f"Vowels in '{text}': {count}") # 3
# Using built-in count()
print(text.count("l")) # 3
print(text.count("o")) # 2
# Character frequency counter
sentence = "hello world"
freq = {}
for char in sentence:
if char != " ":
freq[char] = freq.get(char, 0) + 1
print(freq) # {'h': 1, 'e': 1, 'l': 3, 'o': 2, 'w': 1, 'r': 1, 'd': 1}
7.7 String Formatting
Python
name = "Alice"
age = 25
gpa = 3.856
# Method 1: f-strings (Python 3.6+, RECOMMENDED)
print(f"Name: {name}, Age: {age}")
print(f"GPA: {gpa:.2f}") # GPA: 3.86
print(f"{'Python':>15}") # Right-aligned
print(f"{'Python':<15}") # Left-aligned
print(f"{'Python':^15}") # Center-aligned
print(f"{42:08d}") # 00000042 (zero-padded)
# Method 2: .format()
print("Name: {}, Age: {}".format(name, age))
print("Name: {n}, Age: {a}".format(n=name, a=age))
# Method 3: %-formatting (old style)
print("Name: %s, Age: %d, GPA: %.2f" % (name, age, gpa))
7.8 String Immutability
Strings in Python are immutable โ you cannot change individual characters. To "modify" a string, you create a new one.
Python
text = "Hello"
# text[0] = "h" โ TypeError: 'str' object does not support item assignment
# Create a new string instead
new_text = "h" + text[1:]
print(new_text) # hello
# Or use replace()
new_text = text.replace("H", "h")
print(new_text) # hello
7.9 String Testing Methods
Python
print("12345".isdigit()) # True
print("hello".isalpha()) # True
print("abc123".isalnum()) # True
print("HELLO".isupper()) # True
print("hello".islower()) # True
print(" ".isspace()) # True
print("Hello World".istitle()) # True
# Practical: validate input
pin = input("Enter 4-digit PIN: ")
if pin.isdigit() and len(pin) == 4:
print("Valid PIN โ
")
else:
print("Invalid PIN โ")
Exercises
Exercise 7.1: Count the number of words, vowels, and consonants in a string
Python
text = input("Enter a sentence: ")
words = len(text.split())
vowels = sum(1 for c in text.lower() if c in "aeiou")
consonants = sum(1 for c in text.lower() if c.isalpha() and c not in "aeiou")
print(f"Words: {words}")
print(f"Vowels: {vowels}")
print(f"Consonants: {consonants}")
Exercise 7.2: Write a Caesar cipher encryption function
Python
def caesar_encrypt(text, shift):
"""Encrypt text using Caesar cipher with given shift."""
result = ""
for char in text:
if char.isalpha():
base = ord("A") if char.isupper() else ord("a")
result += chr(((ord(char) - base + shift) % 26) + base)
else:
result += char
return result
message = "Hello World"
encrypted = caesar_encrypt(message, 3)
decrypted = caesar_encrypt(encrypted, -3)
print(f"Original: {message}")
print(f"Encrypted: {encrypted}")
print(f"Decrypted: {decrypted}")
Exercise 7.3: Format a student report card using f-strings
Python
students = [
("Alice", [85, 92, 78]),
("Bob", [90, 88, 95]),
("Charlie", [72, 68, 75]),
]
print(f"{' Student Report Card ':=^50}")
print(f"{'Name':<12} {'Math':>6} {'Sci':>6} {'Eng':>6} {'Avg':>8}")
print("-" * 50)
for name, marks in students:
avg = sum(marks) / len(marks)
print(f"{name:<12} {marks[0]:>6} {marks[1]:>6} {marks[2]:>6} {avg:>8.1f}")
Industry Application: Log File Parser โ Extracting Timestamps, IPs & Error Levels
At companies like Datadog, Splunk, and Elastic, log parsing is critical for monitoring production systems. Python string methods (split, find, slicing, strip) are used to extract structured data from raw Apache/Nginx log lines โ identifying timestamps, client IP addresses, HTTP methods, and error severity levels.
Python
# Apache Log File Parser
# Extracts structured data from raw log lines
log_lines = [
'192.168.1.105 - - [15/Jun/2025:10:23:01 +0530] "GET /api/users HTTP/1.1" 200 1234',
'10.0.0.42 - admin [15/Jun/2025:10:23:05 +0530] "POST /login HTTP/1.1" 401 89',
'172.16.0.8 - - [15/Jun/2025:10:23:12 +0530] "GET /static/logo.png HTTP/1.1" 404 0',
'192.168.1.200 - - [15/Jun/2025:10:23:18 +0530] "DELETE /api/session HTTP/1.1" 500 56',
]
print("โโโ APACHE LOG PARSER โโโ")
print(f"{'IP':<18} {'Timestamp':<22} {'Method':<8} {'Path':<20} {'Status'}")
print("โ" * 85)
for line in log_lines:
# Extract IP address (first field)
ip = line.split()[0]
# Extract timestamp (between [ and ])
ts_start = line.find("[") + 1
ts_end = line.find("]")
timestamp = line[ts_start:ts_end].split()[0]
# Extract HTTP method and path (between quotes)
q_start = line.find('"') + 1
q_end = line.find('"', q_start)
request = line[q_start:q_end]
method, path, _ = request.split()
# Extract status code (after closing quote)
after_quote = line[q_end + 2:].strip()
status = after_quote.split()[0]
# Color-code status
icon = "โ
" if status.startswith("2") else "โ ๏ธ" if status.startswith("4") else "โ"
print(f"{ip:<18} {timestamp:<22} {method:<8} {path:<20} {icon} {status}")
Quick Quiz โ Chapter 7
Q1. What happens when you try to execute s = "Hello"; s[0] = "J"?
- s becomes "Jello"
- s becomes "JHello"
- TypeError โ strings are immutable
- IndexError โ index out of range
Q2. What is the output of f"Score: {85.6789:.2f}"?
- "Score: 85.6789"
- "Score: 85.68"
- "Score: 85.67"
- "Score: 86"
Q3. What is the key difference between find() and index()?
- find() is faster than index()
- find() returns -1 when not found; index() raises ValueError
- index() returns -1 when not found; find() raises ValueError
- There is no difference
Q4. What is the result of "apple,banana,cherry".split(",") joined back with " | ".join(result)?
- "apple,banana,cherry"
- "apple | banana | cherry"
- "apple|banana|cherry"
- ["apple", "banana", "cherry"]
Q5. What do ord('A') and chr(65) return, respectively?
- "A" and 65
- 65 and "A"
- 1 and "a"
- "65" and "A"
Chapter Summary
- Strings are immutable sequences of characters accessed by index
- Traversal:
for char in stringorwhilewith index - Slicing:
s[start:stop:step]โ reverse with[::-1] - Comparison is lexicographic using Unicode values (
ord(),chr()) find()returns -1 if not found;index()raises ValueError- f-strings (
f"...") are the recommended formatting method - Strings are immutable โ methods return new strings
- Testing methods:
isdigit(),isalpha(),isalnum(),isupper(),islower()
Lists
Learning Objectives
- Create and manipulate lists
- Use list operations, slicing, and comprehensions
- Pass lists to functions (pass by reference)
- Work with nested lists (2D arrays)
8.1 Creating Lists
A list is an ordered, mutable collection that can hold items of any type. Lists are one of Python's most versatile data structures.
Python
# Different ways to create lists
empty = [] # empty list
numbers = [1, 2, 3, 4, 5] # integers
fruits = ["apple", "banana", "cherry"] # strings
mixed = [1, "hello", 3.14, True, None] # mixed types
# Using list() constructor
chars = list("Python")
print(chars) # ['P', 'y', 't', 'h', 'o', 'n']
# Using range()
nums = list(range(1, 6))
print(nums) # [1, 2, 3, 4, 5]
evens = list(range(0, 20, 2))
print(evens) # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
# Length
print(len(fruits)) # 3
8.2 Membership & Accessing Elements
Python
colors = ["red", "green", "blue", "yellow", "purple"]
# Membership testing
print("red" in colors) # True
print("orange" not in colors) # True
# Accessing by index (positive and negative)
print(colors[0]) # red (first)
print(colors[2]) # blue (third)
print(colors[-1]) # purple (last)
print(colors[-2]) # yellow (second from end)
# Lists are MUTABLE โ you can change elements
colors[1] = "lime"
print(colors) # ['red', 'lime', 'blue', 'yellow', 'purple']
8.3 List Operations
Python
# Concatenation (+)
a = [1, 2, 3]
b = [4, 5, 6]
c = a + b
print(c) # [1, 2, 3, 4, 5, 6]
# Repetition (*)
zeros = [0] * 5
print(zeros) # [0, 0, 0, 0, 0]
# append() โ add ONE item to the end
fruits = ["apple", "banana"]
fruits.append("cherry")
print(fruits) # ['apple', 'banana', 'cherry']
# extend() โ add ALL items from another list
fruits.extend(["date", "elderberry"])
print(fruits) # ['apple', 'banana', 'cherry', 'date', 'elderberry']
# insert(index, item) โ add at specific position
fruits.insert(1, "blueberry")
print(fruits) # ['apple', 'blueberry', 'banana', 'cherry', ...]
append() vs extend()
append([4,5]) adds the list as a single item: [1, 2, 3, [4, 5]]. extend([4,5]) adds each item individually: [1, 2, 3, 4, 5].
8.4 List Slicing
Python
nums = [10, 20, 30, 40, 50, 60, 70, 80]
print(nums[2:5]) # [30, 40, 50]
print(nums[:3]) # [10, 20, 30] (first 3)
print(nums[5:]) # [60, 70, 80] (from index 5)
print(nums[::-1]) # [80, 70, 60, 50, 40, 30, 20, 10] (reversed)
print(nums[0:8:2]) # [10, 30, 50, 70] (every 2nd)
# Slice assignment (mutate in-place)
nums[1:3] = [200, 300]
print(nums) # [10, 200, 300, 40, 50, 60, 70, 80]
8.5 Deleting Elements
Python
items = ["a", "b", "c", "d", "e"]
# del โ delete by index
del items[0]
print(items) # ['b', 'c', 'd', 'e']
# remove() โ delete by value (first occurrence)
items.remove("c")
print(items) # ['b', 'd', 'e']
# pop() โ remove and return (by index, default last)
last = items.pop()
print(last, items) # e ['b', 'd']
first = items.pop(0)
print(first, items) # b ['d']
# clear() โ remove ALL elements
items.clear()
print(items) # []
8.6 List Comprehensions
List comprehensions provide a concise, Pythonic way to create lists.
Python
# Basic comprehension
squares = [x ** 2 for x in range(1, 6)]
print(squares) # [1, 4, 9, 16, 25]
# With condition (filter)
evens = [x for x in range(1, 21) if x % 2 == 0]
print(evens) # [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
# Transform strings
words = ["hello", "world", "python"]
upper = [w.upper() for w in words]
print(upper) # ['HELLO', 'WORLD', 'PYTHON']
# Conditional expression in comprehension
labels = ["even" if x % 2 == 0 else "odd" for x in range(1, 6)]
print(labels) # ['odd', 'even', 'odd', 'even', 'odd']
# Flatten a 2D list
matrix = [[1, 2], [3, 4], [5, 6]]
flat = [num for row in matrix for num in row]
print(flat) # [1, 2, 3, 4, 5, 6]
8.7 Lists and For Loops
Python
scores = [85, 92, 78, 96, 88]
# Iterate directly
for score in scores:
print(f"Score: {score}")
# With enumerate (index + value)
for i, score in enumerate(scores, 1):
print(f"Student {i}: {score}")
# Calculate statistics
total = sum(scores)
avg = total / len(scores)
highest = max(scores)
lowest = min(scores)
print(f"Total: {total}, Avg: {avg:.1f}")
print(f"Highest: {highest}, Lowest: {lowest}")
8.8 Lists as Function Parameters
Lists are passed to functions by reference โ changes inside the function affect the original list.
Python
def double_values(lst):
"""Double each value in the list IN PLACE."""
for i in range(len(lst)):
lst[i] *= 2
numbers = [1, 2, 3, 4, 5]
double_values(numbers)
print(numbers) # [2, 4, 6, 8, 10] โ original is modified!
# To avoid modifying original, pass a copy
original = [1, 2, 3]
double_values(original[:]) # pass a slice copy
print(original) # [1, 2, 3] โ unchanged!
# Or use .copy()
copy = original.copy()
double_values(copy)
print(original, copy) # [1, 2, 3] [2, 4, 6]
8.9 Nested Lists (2D Arrays)
Python
# 2D list (matrix)
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
# Access element: matrix[row][col]
print(matrix[0][0]) # 1 (top-left)
print(matrix[1][2]) # 6 (row 1, col 2)
print(matrix[-1][-1]) # 9 (bottom-right)
# Print matrix nicely
for row in matrix:
for val in row:
print(f"{val:4}", end="")
print()
# Create 3x3 matrix with comprehension
grid = [[0] * 3 for _ in range(3)]
print(grid) # [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
# Transpose a matrix
transposed = [[matrix[j][i] for j in range(len(matrix))] for i in range(len(matrix[0]))]
print(transposed) # [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
8.10 Common List Methods
| Method | Description | Example |
|---|---|---|
sort() | Sort in place | [3,1,2].sort() โ [1,2,3] |
reverse() | Reverse in place | [1,2,3].reverse() โ [3,2,1] |
count(x) | Count occurrences of x | [1,2,2,3].count(2) โ 2 |
index(x) | First index of x | [1,2,3].index(2) โ 1 |
copy() | Shallow copy | b = a.copy() |
sorted() | Return new sorted list | sorted([3,1,2]) โ [1,2,3] |
Python
nums = [3, 1, 4, 1, 5, 9, 2, 6]
# sort() modifies in place
nums.sort()
print(nums) # [1, 1, 2, 3, 4, 5, 6, 9]
# sort(reverse=True) for descending
nums.sort(reverse=True)
print(nums) # [9, 6, 5, 4, 3, 2, 1, 1]
# sorted() returns NEW list
original = [5, 3, 8, 1]
sorted_list = sorted(original)
print(original) # [5, 3, 8, 1] (unchanged)
print(sorted_list) # [1, 3, 5, 8]
# Sort strings by length
words = ["banana", "pie", "apple", "kiwi"]
words.sort(key=len)
print(words) # ['pie', 'kiwi', 'apple', 'banana']
Exercises
Exercise 8.1: Write a program to remove duplicates from a list
Python
# Method 1: Using a loop
original = [1, 2, 3, 2, 4, 1, 5, 3]
unique = []
for item in original:
if item not in unique:
unique.append(item)
print(f"Original: {original}")
print(f"Unique: {unique}")
# Method 2: Using set (doesn't preserve order in older Python)
unique2 = list(dict.fromkeys(original))
print(f"Unique2: {unique2}")
Exercise 8.2: Implement a function to rotate a list by n positions
Python
def rotate_list(lst, n):
"""Rotate list left by n positions."""
n = n % len(lst) # handle n > length
return lst[n:] + lst[:n]
data = [1, 2, 3, 4, 5]
print(f"Original: {data}")
print(f"Rotate by 2: {rotate_list(data, 2)}")
print(f"Rotate by 4: {rotate_list(data, 4)}")
Exercise 8.3: Matrix addition using nested lists
Python
def matrix_add(A, B):
"""Add two matrices and return the result."""
rows = len(A)
cols = len(A[0])
result = [[A[i][j] + B[i][j] for j in range(cols)] for i in range(rows)]
return result
A = [[1, 2, 3], [4, 5, 6]]
B = [[7, 8, 9], [10, 11, 12]]
C = matrix_add(A, B)
print("Matrix A + B =")
for row in C:
print([f"{v:3}" for v in row])
Industry Application: E-commerce Product Recommendation Engine
At companies like Amazon, Netflix, and Spotify, recommendation engines analyze purchase history stored as lists to find common items between users and suggest products based on co-purchase patterns. List operations like intersection, set conversion, and frequency counting are fundamental to building collaborative filtering algorithms at scale.
Python
from collections import Counter
# Purchase history (list of lists)
purchase_history = {
"Alice": ["Laptop", "Mouse", "Keyboard", "USB Hub", "Webcam"],
"Bob": ["Laptop", "Mouse", "Monitor", "Headphones"],
"Charlie": ["Keyboard", "Mouse", "USB Hub", "Monitor"],
"Diana": ["Laptop", "Webcam", "Headphones", "Monitor"],
}
def find_common_items(user1, user2):
"""Find items purchased by both users."""
return [item for item in user1 if item in user2]
def recommend_products(target_user, all_history):
"""Recommend products based on co-purchase patterns."""
target_items = all_history[target_user]
recommendations = []
for user, items in all_history.items():
if user == target_user:
continue
common = find_common_items(target_items, items)
if len(common) >= 2: # Similar user threshold
new_items = [i for i in items if i not in target_items]
recommendations.extend(new_items)
# Rank by frequency
freq = Counter(recommendations)
return freq.most_common(3)
# Generate recommendations for Alice
target = "Alice"
recs = recommend_products(target, purchase_history)
print("โ" * 45)
print(f"๐ RECOMMENDATIONS FOR {target.upper()}")
print("โ" * 45)
print(f"Purchased: {purchase_history[target]}")
print(f"\nTop Recommendations:")
for i, (product, score) in enumerate(recs, 1):
print(f" {i}. {product} (matched by {score} similar users)")
print("โ" * 45)
Quick Quiz โ Chapter 8
Q1. What does it mean that Python lists are "mutable"?
- They can only store strings
- Their elements can be changed after creation
- They have a fixed maximum size
- They are stored in read-only memory
Q2. What is the difference between append() and extend()?
- append() adds multiple items; extend() adds one item
- append() adds one element; extend() adds each element of an iterable
- Both do the same thing
- extend() creates a new list; append() modifies in place
Q3. What is the output of [x*2 for x in range(4)]?
- [2, 4, 6, 8]
- [0, 2, 4, 6]
- [1, 2, 3, 4]
- [0, 1, 2, 3]
Q4. When a list is passed to a function, what happens?
- A copy is automatically created
- The function receives a reference โ changes affect the original list
- The list becomes immutable inside the function
- Python creates a tuple from the list
Q5. What is the difference between del list[i] and list.remove(x)?
- del removes by value; remove() by index
- del removes by index; remove() removes the first occurrence of a value
- Both remove by index
- del can only remove the last element
Chapter Summary
- Lists are ordered, mutable collections:
[],list(),list(range()) - Access by index:
list[0](first),list[-1](last) - Membership:
in,not in - Operations:
+(concat),*(repeat),append(),extend(),insert() - Slicing:
list[start:stop:step]โ same syntax as strings - Deletion:
del,remove(),pop(),clear() - List comprehensions:
[expr for x in iterable if condition] - Lists are passed by reference โ changes inside functions affect the original
- Nested lists act as 2D arrays:
matrix[row][col] - Key methods:
sort(),reverse(),count(),index(),copy()
Tuples & Dictionaries
Learning Objectives
- Understand tuples, immutability, and packing/unpacking
- Use tuples as return values and in assignments
- Create and manipulate dictionaries
- Implement sparse matrices with dictionaries
- Understand aliasing vs copying
9.1 Creating Tuples
A tuple is an ordered, immutable sequence. Once created, you cannot add, remove, or change elements. Tuples use parentheses () instead of square brackets.
Python
# Creating tuples
empty = () # Empty tuple
single = (42,) # Single element โ trailing comma required!
coords = (3, 4) # Two elements
colors = ("red", "green", "blue") # Three strings
mixed = (1, "hello", 3.14, True) # Mixed types
# Using tuple() constructor
from_list = tuple([1, 2, 3]) # From a list
from_str = tuple("hello") # ('h','e','l','l','o')
from_range = tuple(range(5)) # (0,1,2,3,4)
# Without parentheses (tuple packing)
point = 10, 20, 30 # Also a tuple!
print(type(point)) # <class 'tuple'>
Single Element Trap
x = (42) is just an integer in parentheses โ not a tuple. You need a trailing comma: x = (42,) to make it a tuple.
9.2 Tuple Immutability
Unlike lists, tuples cannot be modified after creation. This makes them hashable, so they can be used as dictionary keys and set elements.
Python
t = (1, 2, 3)
# t[0] = 10 # โ TypeError: 'tuple' does not support item assignment
# t.append(4) # โ AttributeError: no attribute 'append'
# Read-only access works fine
print(t[0]) # 1
print(t[-1]) # 3
print(t[1:3]) # (2, 3)
| Feature | List | Tuple |
|---|---|---|
| Syntax | [1, 2, 3] | (1, 2, 3) |
| Mutable? | โ Yes | โ No |
| Hashable? | โ No | โ Yes |
| As dict key? | โ No | โ Yes |
| Performance | Slower | Faster |
| Use case | Changing data | Fixed data, records |
9.3 Tuple Packing & Unpacking
Packing assigns multiple values to a single tuple. Unpacking extracts values into individual variables.
Python
# Packing
person = "Alice", 25, "Engineer"
# Unpacking
name, age, job = person
print(name) # Alice
print(age) # 25
# Swap variables elegantly
a, b = 10, 20
a, b = b, a
print(a, b) # 20 10
# Extended unpacking with *
first, *rest = (1, 2, 3, 4, 5)
print(first) # 1
print(rest) # [2, 3, 4, 5]
first, *middle, last = (1, 2, 3, 4, 5)
print(middle) # [2, 3, 4]
9.4 Tuples as Return Values
Python
def min_max(numbers):
"""Return both minimum and maximum."""
return min(numbers), max(numbers)
lowest, highest = min_max([4, 1, 7, 2, 9])
print(f"Min: {lowest}, Max: {highest}")
def divide(a, b):
"""Return quotient and remainder."""
return a // b, a % b
q, r = divide(17, 5)
print(f"17 รท 5 = {q} remainder {r}")
9.5 Named Tuples
Python
from collections import namedtuple
Student = namedtuple("Student", ["name", "age", "grade"])
s1 = Student("Alice", 20, "A")
print(s1.name) # Alice
print(s1[1]) # 20
print(s1) # Student(name='Alice', age=20, grade='A')
Point = namedtuple("Point", "x y")
p = Point(3, 4)
print(f"Distance: {(p.x**2 + p.y**2)**0.5:.2f}")
9.6 Creating Dictionaries
A dictionary maps keys to values. Keys must be immutable (strings, numbers, tuples).
Python
empty = {}
student = {"name": "Alice", "age": 20, "grade": "A"}
scores = dict(math=95, physics=88, chem=92)
from_pairs = dict([("a", 1), ("b", 2)])
from_zip = dict(zip(["x","y"], [10,20]))
print(student)
9.7 Dictionary Operations
Python
d = {"name": "Alice", "age": 20}
print(d["name"]) # Alice
print(d.get("email", "N/A")) # N/A (safe access)
d.setdefault("grade", "B") # Sets "B" since missing
d["email"] = "alice@mail.com" # Add new key
d["age"] = 21 # Update existing
print("name" in d) # True
print(len(d)) # 4
9.8 Dictionary Methods
Python
d = {"a": 1, "b": 2, "c": 3}
print(d.keys()) # dict_keys(['a', 'b', 'c'])
print(d.values()) # dict_values([1, 2, 3])
print(d.items()) # dict_items([('a',1), ('b',2), ('c',3)])
for key, value in d.items():
print(f"{key} โ {value}")
d.update({"d": 4, "a": 100}) # Adds 'd', updates 'a'
val = d.pop("b") # Returns 2, removes 'b'
d.clear() # Removes all items
9.9 Sparse Matrices with Dictionaries
Python
# Matrix: [[0,0,3], [0,5,0], [7,0,0]]
sparse = {(0,2): 3, (1,1): 5, (2,0): 7}
def get_element(matrix, row, col):
return matrix.get((row, col), 0)
print(get_element(sparse, 0, 2)) # 3
print(get_element(sparse, 0, 0)) # 0 (not stored)
9.10 Aliasing vs Copying
Python
import copy
# Aliasing โ same object
a = {"x": [1, 2], "y": 3}
b = a
b["y"] = 99
print(a["y"]) # 99 โ a affected!
# Shallow copy โ nested objects shared
a = {"x": [1, 2], "y": 3}
b = a.copy()
b["x"].append(3)
print(a["x"]) # [1, 2, 3] โ shared!
# Deep copy โ fully independent
a = {"x": [1, 2], "y": 3}
b = copy.deepcopy(a)
b["x"].append(3)
print(a["x"]) # [1, 2] โ NOT affected
9.11 Dictionary Comprehensions
Python
squares = {x: x**2 for x in range(1, 6)}
print(squares) # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
# Swap keys and values
original = {"a": 1, "b": 2}
swapped = {v: k for k, v in original.items()}
# Word frequency
text = "apple banana apple cherry banana apple"
words = text.split()
freq = {}
for w in words:
freq[w] = freq.get(w, 0) + 1
print(freq) # {'apple': 3, 'banana': 2, 'cherry': 1}
Exercises
Exercise 9.1: Write a function that returns the name with the highest score from a list of (name, score) tuples
Python
def top_scorer(students):
best_name, best_score = students[0]
for name, score in students[1:]:
if score > best_score:
best_name, best_score = name, score
return best_name
data = [("Alice", 85), ("Bob", 92), ("Charlie", 78)]
print(top_scorer(data)) # Bob
Exercise 9.2: Create a dictionary mapping each character in a string to its frequency
Python
def char_frequency(s):
return {ch: s.count(ch) for ch in set(s)}
print(char_frequency("hello"))
# {'h': 1, 'e': 1, 'l': 2, 'o': 1}
Exercise 9.3: Invert a dictionary โ swap keys and values, handling duplicate values
Python
def invert_dict(d):
inverted = {}
for key, val in d.items():
inverted.setdefault(val, []).append(key)
return inverted
grades = {"Alice": "A", "Bob": "B", "Charlie": "A"}
print(invert_dict(grades))
# {'A': ['Alice', 'Charlie'], 'B': ['Bob']}
Industry Application: Application Configuration Manager
At companies like Docker, Kubernetes, and HashiCorp, configuration management is critical. Python dictionaries are used to load application settings, merge default configs with environment-specific overrides, and validate that all required keys are present โ ensuring reliable deployments across dev, staging, and production environments.
Python
import copy
def load_config(defaults, overrides):
"""Merge default config with environment overrides (deep merge)."""
config = copy.deepcopy(defaults)
for key, value in overrides.items():
if isinstance(value, dict) and key in config:
config[key] = load_config(config[key], value)
else:
config[key] = value
return config
def validate_config(config, required_keys):
"""Validate that all required keys exist in config."""
missing = [k for k in required_keys if k not in config]
if missing:
raise KeyError(f"Missing required keys: {missing}")
return True
# Default configuration
defaults = {
"app_name": "MyApp",
"debug": False,
"database": {
"host": "localhost",
"port": 5432,
"name": "mydb",
},
"cache_ttl": 300,
"max_connections": 100,
}
# Production overrides
prod_overrides = {
"debug": False,
"database": {
"host": "db.prod.company.com",
"port": 5432,
},
"max_connections": 500,
}
# Merge and validate
config = load_config(defaults, prod_overrides)
required = ("app_name", "database", "max_connections") # tuple of required keys
print("โ" * 45)
print("โ๏ธ APPLICATION CONFIGURATION")
print("โ" * 45)
for key, value in config.items():
if isinstance(value, dict):
print(f" {key}:")
for k, v in value.items():
print(f" {k}: {v}")
else:
print(f" {key}: {value}")
print("โ" * 45)
print(f"โ
Config valid: {validate_config(config, required)}")
Quick Quiz โ Chapter 9
Q1. Why are tuples immutable in Python?
- To save memory during iteration
- To ensure data integrity โ once created, elements cannot be changed
- Because Python lists are already mutable
- To allow faster printing
Q2. What is the correct way to create a single-element tuple?
- t = (42)
- t = (42,)
- t = tuple[42]
- t = {42}
Q3. What happens when you use dict[key] with a non-existent key vs dict.get(key)?
- Both return None
- [] raises KeyError; get() returns None (or a default)
- get() raises KeyError; [] returns None
- Both raise KeyError
Q4. What does dict.setdefault(key, value) do?
- Always sets the key to the given value
- Returns the value if key exists; otherwise sets it and returns it
- Removes the key from the dictionary
- Raises an error if the key doesn't exist
Q5. When should you use copy.deepcopy() instead of dict.copy()?
- When the dictionary has string keys
- When the dictionary contains nested mutable objects (lists, dicts)
- When the dictionary is empty
- deepcopy is always slower and never needed
Chapter Summary
- Tuples are immutable ordered sequences โ use
()ortuple() - Single-element tuple needs trailing comma:
(42,) - Tuple unpacking:
a, b, c = (1, 2, 3) - Tuples are hashable โ can be dictionary keys
- Named tuples from
collections.namedtuplefor readable records - Dictionaries:
{key: value}โ keys must be immutable - Use
get()for safe access,setdefault()for missing keys - Shallow copy shares nested objects;
deepcopy()is independent - Dict comprehensions:
{k: v for k, v in iterable}
Object-Oriented Programming
Classes, objects & inheritance
Classes & Objects
Learning Objectives
- Create classes with __init__ constructors
- Define instance and class attributes
- Create instance objects and access attributes
- Implement __str__ and __repr__ methods
10.1 OOP Concepts
Object-Oriented Programming (OOP) organizes code around objects โ data bundled with the functions that operate on it. A class is a blueprint; an object is an instance of that blueprint.
| Term | Description | Example |
|---|---|---|
| Class | Blueprint/template for objects | class Dog: |
| Object | Instance of a class | my_dog = Dog() |
| Attribute | Data stored in an object | my_dog.name |
| Method | Function defined inside a class | my_dog.bark() |
10.2 Creating a Class
Python
class Dog:
"""A simple Dog class."""
def __init__(self, name, breed, age):
# Instance attributes โ unique to each object
self.name = name
self.breed = breed
self.age = age
def bark(self):
return f"{self.name} says: Woof!"
def info(self):
return f"{self.name} is a {self.age}-year-old {self.breed}"
# Creating objects (instances)
dog1 = Dog("Buddy", "Golden Retriever", 3)
dog2 = Dog("Max", "German Shepherd", 5)
print(dog1.bark())
print(dog2.info())
The self Parameter
self refers to the current instance of the class. It must be the first parameter of every instance method. Python passes it automatically when you call dog1.bark() โ you don't pass it yourself.
10.3 Instance vs Class Attributes
Python
class Student:
# Class attribute โ shared by ALL instances
school = "EduArtha University"
count = 0
def __init__(self, name, roll_no):
# Instance attributes โ unique to each object
self.name = name
self.roll_no = roll_no
Student.count += 1
s1 = Student("Alice", 101)
s2 = Student("Bob", 102)
print(s1.school) # EduArtha University (class attr)
print(s2.school) # EduArtha University (same)
print(s1.name) # Alice (instance attr)
print(Student.count) # 2 (class attr)
10.4 The __str__ and __repr__ Methods
Python
class Student:
def __init__(self, name, grade):
self.name = name
self.grade = grade
def __str__(self):
"""Human-readable string (for print/str)."""
return f"{self.name} (Grade: {self.grade})"
def __repr__(self):
"""Developer-readable string (for debugging)."""
return f"Student('{self.name}', '{self.grade}')"
s = Student("Alice", "A")
print(s) # Calls __str__: Alice (Grade: A)
print(repr(s)) # Calls __repr__: Student('Alice', 'A')
10.5 Complete Example: BankAccount Class
Python
class BankAccount:
"""A simple bank account with deposit and withdraw."""
def __init__(self, owner, balance=0):
self.owner = owner
self.balance = balance
def deposit(self, amount):
if amount > 0:
self.balance += amount
print(f"Deposited โน{amount}. Balance: โน{self.balance}")
else:
print("Amount must be positive!")
def withdraw(self, amount):
if amount > self.balance:
print("Insufficient funds!")
elif amount <= 0:
print("Amount must be positive!")
else:
self.balance -= amount
print(f"Withdrew โน{amount}. Balance: โน{self.balance}")
def __str__(self):
return f"Account({self.owner}, โน{self.balance})"
acc = BankAccount("Alice", 1000)
acc.deposit(500)
acc.withdraw(200)
acc.withdraw(2000)
print(acc)
Exercises
Exercise 10.1: Create a Rectangle class with length, width, area(), and perimeter() methods
Python
class Rectangle:
def __init__(self, length, width):
self.length = length
self.width = width
def area(self):
return self.length * self.width
def perimeter(self):
return 2 * (self.length + self.width)
def __str__(self):
return f"Rectangle({self.length}x{self.width})"
r = Rectangle(5, 3)
print(f"Area: {r.area()}, Perimeter: {r.perimeter()}")
# Area: 15, Perimeter: 16
Exercise 10.2: Create a Student class that tracks grades and calculates GPA
Python
class Student:
def __init__(self, name):
self.name = name
self.grades = []
def add_grade(self, grade):
self.grades.append(grade)
def gpa(self):
if not self.grades:
return 0
return sum(self.grades) / len(self.grades)
def __str__(self):
return f"{self.name}: GPA={self.gpa():.2f}"
s = Student("Alice")
s.add_grade(90)
s.add_grade(85)
s.add_grade(92)
print(s) # Alice: GPA=89.00
Exercise 10.3: Create a Counter class with increment, decrement, and reset methods
Python
class Counter:
def __init__(self, start=0):
self.value = start
def increment(self):
self.value += 1
def decrement(self):
self.value -= 1
def reset(self):
self.value = 0
def __str__(self):
return f"Counter({self.value})"
c = Counter()
c.increment()
c.increment()
c.increment()
c.decrement()
print(c) # Counter(2)
Industry Application: E-commerce Product Inventory System
At companies like Amazon, Walmart, and Myntra, inventory management systems use OOP to model products with SKU codes, track stock levels in real-time, and trigger automated low-stock alerts. Each product is an object with attributes (name, price, stock) and methods (restock, sell, check alerts) โ enabling clean, scalable warehouse management.
Python
class Product:
"""E-commerce product with inventory tracking."""
_id_counter = 0
def __init__(self, name, price, stock, low_threshold=5):
Product._id_counter += 1
self.sku = f"SKU-{Product._id_counter:04d}"
self.name = name
self.price = price
self.stock = stock
self.low_threshold = low_threshold
def sell(self, qty):
if qty > self.stock:
print(f" โ Only {self.stock} units available!")
return False
self.stock -= qty
print(f" โ
Sold {qty}x {self.name} (โน{qty * self.price:,.2f})")
self._check_alert()
return True
def restock(self, qty):
self.stock += qty
print(f" ๐ฆ Restocked {qty}x {self.name}. Stock: {self.stock}")
def _check_alert(self):
if self.stock <= self.low_threshold:
print(f" โ ๏ธ LOW STOCK ALERT: {self.name} only {self.stock} left!")
def __str__(self):
return f"[{self.sku}] {self.name} โ โน{self.price:,.2f} | Stock: {self.stock}"
def __repr__(self):
return f"Product('{self.name}', {self.price}, {self.stock})"
# Create inventory
inventory = [
Product("Wireless Mouse", 599, 50),
Product("Mechanical Keyboard", 2499, 8),
Product("USB-C Hub", 1299, 3, low_threshold=5),
]
print("โ" * 50)
print("๐ช PRODUCT INVENTORY DASHBOARD")
print("โ" * 50)
for p in inventory:
print(p)
print("\n๐ Processing Orders...")
inventory[0].sell(5)
inventory[1].sell(6)
inventory[2].sell(2)
inventory[2].restock(20)
Quick Quiz โ Chapter 10
Q1. What is the purpose of the __init__ method?
- To destroy an object
- To initialize the object's attributes when it is created
- To define class-level constants
- To import required modules
Q2. Why is self required as the first parameter in instance methods?
- It's a Python keyword that cannot be changed
- It refers to the current instance, allowing access to its attributes
- It creates a copy of the object
- It makes the method static
Q3. What is the difference between class attributes and instance attributes?
- Class attributes are faster to access
- Class attributes are shared by all instances; instance attributes are unique per object
- Instance attributes can only be numbers
- There is no difference
Q4. What does the __str__ method control?
- How the object is deleted
- The string representation shown by print() and str()
- The size of the object in memory
- The class name of the object
Q5. How do you create an object (instance) of a class Car with argument "Tesla"?
- Car.new("Tesla")
- new Car("Tesla")
- Car("Tesla")
- create Car("Tesla")
Chapter Summary
- A class is a blueprint; an object is an instance
__init__is the constructor โ called automatically when creating objectsselfrefers to the current instance โ always the first method parameter- Instance attributes are unique per object; class attributes are shared
__str__for human-readable output;__repr__for developer debugging- Methods are functions defined inside a class that operate on instance data
Inheritance & Advanced OOP
Learning Objectives
- Implement single and multiple inheritance
- Override methods and use super()
- Apply data hiding and encapsulation
- Understand polymorphism and function overloading
11.1 Inheritance Basics
Inheritance lets a child class reuse code from a parent class. The child inherits all attributes and methods, and can add or override them.
Python
class Animal:
def __init__(self, name, species):
self.name = name
self.species = species
def speak(self):
return f"{self.name} makes a sound"
class Dog(Animal): # Dog inherits from Animal
def __init__(self, name, breed):
super().__init__(name, "Dog") # Call parent __init__
self.breed = breed
def speak(self): # Method overriding
return f"{self.name} says: Woof!"
class Cat(Animal):
def speak(self):
return f"{self.name} says: Meow!"
dog = Dog("Buddy", "Labrador")
cat = Cat("Whiskers", "Cat")
print(dog.speak())
print(cat.speak())
print(isinstance(dog, Animal)) # True
11.2 super() and Method Overriding
Python
class Vehicle:
def __init__(self, make, model, year):
self.make = make
self.model = model
self.year = year
def info(self):
return f"{self.year} {self.make} {self.model}"
class ElectricCar(Vehicle):
def __init__(self, make, model, year, battery_kwh):
super().__init__(make, model, year)
self.battery_kwh = battery_kwh
def info(self): # Override parent method
base = super().info() # Call parent method
return f"{base} (Electric, {self.battery_kwh}kWh)"
car = ElectricCar("Tesla", "Model 3", 2024, 75)
print(car.info())
11.3 Multiple Inheritance & MRO
Python
class Flyable:
def fly(self):
return "I can fly!"
class Swimmable:
def swim(self):
return "I can swim!"
class Duck(Flyable, Swimmable): # Multiple inheritance
def quack(self):
return "Quack!"
d = Duck()
print(d.fly())
print(d.swim())
print(d.quack())
# MRO โ Method Resolution Order
print(Duck.mro())
# [Duck, Flyable, Swimmable, object]
11.4 Data Hiding & Encapsulation
Python
class Account:
def __init__(self, balance):
self.__balance = balance # Name mangling: __balance โ _Account__balance
@property
def balance(self):
"""Getter โ controlled read access."""
return self.__balance
@balance.setter
def balance(self, value):
"""Setter โ with validation."""
if value < 0:
raise ValueError("Balance cannot be negative!")
self.__balance = value
acc = Account(1000)
print(acc.balance) # 1000 (uses getter)
acc.balance = 500 # Uses setter
# acc.balance = -100 # โ ValueError!
# acc.__balance # โ AttributeError (name mangled)
11.5 Polymorphism
Python
class Shape:
def area(self):
raise NotImplementedError
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14159 * self.radius ** 2
class Rectangle(Shape):
def __init__(self, w, h):
self.w = w
self.h = h
def area(self):
return self.w * self.h
# Polymorphism โ same method name, different behavior
shapes = [Circle(5), Rectangle(4, 6), Circle(3)]
for s in shapes:
print(f"{type(s).__name__}: area = {s.area():.2f}")
11.6 Abstract Classes
Python
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self):
pass
@abstractmethod
def perimeter(self):
pass
# shape = Shape() # โ TypeError: Can't instantiate abstract class
class Circle(Shape):
def __init__(self, r):
self.r = r
def area(self):
return 3.14159 * self.r ** 2
def perimeter(self):
return 2 * 3.14159 * self.r
11.7 @classmethod and @staticmethod
Python
class Employee:
raise_pct = 1.05
def __init__(self, name, salary):
self.name = name
self.salary = salary
@classmethod
def set_raise(cls, pct):
"""Modifies the class attribute."""
cls.raise_pct = pct
@staticmethod
def is_workday(day):
"""Does not need self or cls."""
return day.weekday() < 5
Employee.set_raise(1.10)
print(Employee.raise_pct) # 1.10
Exercises
Exercise 11.1: Create a Shape hierarchy with Circle and Rectangle that inherit from Shape
Python
import math
class Shape:
def area(self):
raise NotImplementedError
def __str__(self):
return f"{type(self).__name__}: area={self.area():.2f}"
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
return math.pi * self.radius ** 2
class Rectangle(Shape):
def __init__(self, w, h):
self.w, self.h = w, h
def area(self):
return self.w * self.h
print(Circle(5)) # Circle: area=78.54
print(Rectangle(4, 6)) # Rectangle: area=24.00
Exercise 11.2: Create a Person โ Student โ GradStudent inheritance chain
Python
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
class Student(Person):
def __init__(self, name, age, roll_no):
super().__init__(name, age)
self.roll_no = roll_no
class GradStudent(Student):
def __init__(self, name, age, roll_no, thesis):
super().__init__(name, age, roll_no)
self.thesis = thesis
def __str__(self):
return f"{self.name} (Roll:{self.roll_no}) - Thesis: {self.thesis}"
g = GradStudent("Alice", 24, 101, "ML in Healthcare")
print(g)
Exercise 11.3: Implement a class with @property that validates temperature (Celsius โฅ -273.15)
Python
class Temperature:
def __init__(self, celsius):
self.celsius = celsius # Uses setter
@property
def celsius(self):
return self._celsius
@celsius.setter
def celsius(self, value):
if value < -273.15:
raise ValueError("Below absolute zero!")
self._celsius = value
@property
def fahrenheit(self):
return self._celsius * 9/5 + 32
t = Temperature(100)
print(f"{t.celsius}ยฐC = {t.fahrenheit}ยฐF")
# 100ยฐC = 212.0ยฐF
Industry Application: Payment Gateway System
At companies like Razorpay, Stripe, and PayPal, payment processing systems are built using inheritance hierarchies. A base PaymentProcessor class defines the common interface, while child classes like CreditCardPayment, UPIPayment, and WalletPayment implement platform-specific processing logic โ enabling polymorphic payment handling across diverse methods.
Python
from abc import ABC, abstractmethod
from datetime import datetime
class PaymentProcessor(ABC):
"""Abstract base class for all payment methods."""
transaction_count = 0
def __init__(self, amount, customer_id):
self.amount = amount
self.customer_id = customer_id
self.timestamp = datetime.now()
PaymentProcessor.transaction_count += 1
self.txn_id = f"TXN{PaymentProcessor.transaction_count:05d}"
@abstractmethod
def process(self):
pass
def receipt(self):
return f"[{self.txn_id}] โน{self.amount} via {self.__class__.__name__}"
class CreditCardPayment(PaymentProcessor):
def __init__(self, amount, customer_id, card_last4):
super().__init__(amount, customer_id)
self.card_last4 = card_last4
def process(self):
fee = self.amount * 0.02 # 2% processing fee
print(f"๐ณ Credit Card ****{self.card_last4}")
print(f" Amount: โน{self.amount} + Fee: โน{fee:.2f}")
print(f" โ
Payment processed! {self.receipt()}")
class UPIPayment(PaymentProcessor):
def __init__(self, amount, customer_id, upi_id):
super().__init__(amount, customer_id)
self.upi_id = upi_id
def process(self):
print(f"๐ฑ UPI Payment to {self.upi_id}")
print(f" Amount: โน{self.amount} (No extra fee)")
print(f" โ
Payment processed! {self.receipt()}")
class WalletPayment(PaymentProcessor):
def __init__(self, amount, customer_id, wallet_name):
super().__init__(amount, customer_id)
self.wallet_name = wallet_name
def process(self):
cashback = self.amount * 0.05 # 5% cashback
print(f"๐ {self.wallet_name} Wallet")
print(f" Amount: โน{self.amount} | Cashback: โน{cashback:.2f}")
print(f" โ
Payment processed! {self.receipt()}")
# Polymorphic payment processing
payments = [
CreditCardPayment(5000, "CUST001", "4242"),
UPIPayment(1500, "CUST002", "user@paytm"),
WalletPayment(800, "CUST003", "PhonePe"),
]
print("โ" * 45)
print("๐ฐ PAYMENT GATEWAY โ TRANSACTIONS")
print("โ" * 45)
for payment in payments:
payment.process()
print()
Quick Quiz โ Chapter 11
Q1. What does super().__init__() do in a child class?
- Creates a new parent object
- Calls the parent class's constructor to initialize inherited attributes
- Overrides the parent's __init__ method
- Returns the parent class name
Q2. What is method overriding in Python?
- Defining two methods with the same name in the same class
- A child class redefining a method inherited from the parent class
- Calling a method multiple times
- Making a method private
Q3. What determines the method resolution order (MRO) in multiple inheritance?
- Alphabetical order of class names
- The C3 linearization algorithm
- Random selection at runtime
- The order methods are defined
Q4. What does the @property decorator do?
- Makes a method static
- Makes an attribute read-only by default, with optional setter
- Converts a method into a class method
- Prevents method overriding
Q5. Which module provides the ABC class and @abstractmethod decorator?
- abstract
- abc
- interface
- meta
Chapter Summary
- Inheritance: child class reuses parent code โ
class Child(Parent) super()calls parent methods โ use in__init__and overridden methods- Method overriding: child redefines parent method with same name
- Multiple inheritance: inherit from multiple classes; MRO determines order
- Name mangling:
__attrbecomes_Class__attrfor data hiding @propertycreates getter/setter for controlled attribute access- Polymorphism: same method name, different behavior across classes
- Abstract classes (ABC): define interfaces that must be implemented
@classmethodworks on the class;@staticmethodis a utility function
Files & Advanced Topics
File handling, exceptions & regular expressions
File Handling & Exceptions
Learning Objectives
- Read and write text and binary files
- Use context managers (with statement)
- Handle exceptions with try-except-else-finally
- Work with directories using the os module
- Serialize objects with pickle
12.1 Opening Files
Use open() to work with files. Always prefer the with statement โ it automatically closes the file.
| Mode | Description |
|---|---|
'r' | Read (default). File must exist. |
'w' | Write. Creates new / overwrites existing. |
'a' | Append. Creates if doesn't exist. |
'r+' | Read + Write. File must exist. |
'b' | Binary mode (add to any: 'rb', 'wb'). |
12.2 Reading Files
Python
# Always use 'with' โ it auto-closes the file
with open("data.txt", "r") as f:
content = f.read() # Read entire file as string
print(content)
with open("data.txt") as f:
line = f.readline() # Read one line
print(line)
with open("data.txt") as f:
lines = f.readlines() # Read all lines โ list
print(lines)
# Best practice: iterate line by line (memory efficient)
with open("data.txt") as f:
for line in f:
print(line.strip()) # strip() removes \n
12.3 Writing Files
Python
# Write (creates new or overwrites)
with open("output.txt", "w") as f:
f.write("Hello, World!\n")
f.write("Second line\n")
# Append (adds to end)
with open("output.txt", "a") as f:
f.write("Appended line\n")
# Write multiple lines
lines = ["Line 1\n", "Line 2\n", "Line 3\n"]
with open("output.txt", "w") as f:
f.writelines(lines)
# Writing variables (must convert to string)
name = "Alice"
age = 25
with open("output.txt", "w") as f:
f.write(f"Name: {name}\nAge: {age}\n")
Always Use 'with'!
The with statement is a context manager that guarantees the file is closed, even if an exception occurs. Never use f = open(...) without with unless absolutely necessary.
12.4 Working with Directories
Python
import os
# List directory contents
print(os.listdir(".")) # List current directory
# Check if file/directory exists
print(os.path.exists("data.txt")) # True/False
print(os.path.isfile("data.txt")) # True if file
print(os.path.isdir("mydir")) # True if directory
# Create directories
os.makedirs("path/to/dir", exist_ok=True)
# Join paths (cross-platform)
path = os.path.join("folder", "subfolder", "file.txt")
print(path) # folder/subfolder/file.txt
12.5 Pickling (Binary Serialization)
Python
import pickle
# Save Python object to binary file
data = {"name": "Alice", "scores": [90, 85, 92]}
with open("data.pkl", "wb") as f:
pickle.dump(data, f)
# Load Python object from binary file
with open("data.pkl", "rb") as f:
loaded = pickle.load(f)
print(loaded)
12.6 Exception Handling
Python
# Basic try-except
try:
num = int(input("Enter a number: "))
result = 10 / num
except ValueError:
print("Not a valid number!")
except ZeroDivisionError:
print("Cannot divide by zero!")
else:
print(f"Result: {result}") # Runs if NO exception
finally:
print("This always runs.") # Cleanup code
12.7 Common Exceptions
| Exception | When It Occurs |
|---|---|
ZeroDivisionError | 10 / 0 |
FileNotFoundError | open("missing.txt") |
ValueError | int("hello") |
TypeError | "hello" + 5 |
IndexError | lst[100] on a short list |
KeyError | dict["missing_key"] |
AttributeError | Calling method that doesn't exist |
12.8 Custom Exceptions & raise
Python
class InsufficientFundsError(Exception):
def __init__(self, balance, amount):
self.balance = balance
self.amount = amount
super().__init__(
f"Cannot withdraw โน{amount}. Balance: โน{balance}"
)
def withdraw(balance, amount):
if amount > balance:
raise InsufficientFundsError(balance, amount)
return balance - amount
try:
withdraw(100, 500)
except InsufficientFundsError as e:
print(e)
Exercises
Exercise 12.1: Write a program to count words in a text file
Python
def count_words(filename):
try:
with open(filename) as f:
content = f.read()
words = content.split()
print(f"Total words: {len(words)}")
except FileNotFoundError:
print(f"File '{filename}' not found!")
count_words("sample.txt")
Exercise 12.2: Copy a file, handling errors gracefully
Python
def copy_file(src, dst):
try:
with open(src, "r") as fin, open(dst, "w") as fout:
fout.write(fin.read())
print(f"Copied {src} โ {dst}")
except FileNotFoundError:
print(f"Source file '{src}' not found!")
except PermissionError:
print("Permission denied!")
copy_file("input.txt", "backup.txt")
Exercise 12.3: Save and load a list of student records using pickle
Python
import pickle
students = [
{"name": "Alice", "roll": 101, "marks": 92},
{"name": "Bob", "roll": 102, "marks": 85},
]
# Save
with open("students.pkl", "wb") as f:
pickle.dump(students, f)
# Load
with open("students.pkl", "rb") as f:
Exercise 12.2: Write a safe division function that handles all errors
Python
def safe_divide():
try:
a = float(input("Enter numerator: "))
b = float(input("Enter denominator: "))
result = a / b
except ValueError:
print("Invalid input โ enter numbers only!")
except ZeroDivisionError:
print("Cannot divide by zero!")
else:
print(f"Result: {a} / {b} = {result:.4f}")
finally:
print("Calculation attempted.")
safe_divide()
Exercise 12.3: Save and load a list of students using pickle
Python
import pickle
def save_students(students, filename):
with open(filename, "wb") as f:
pickle.dump(students, f)
print(f"Saved {len(students)} students โ
")
def load_students(filename):
try:
with open(filename, "rb") as f:
return pickle.load(f)
except FileNotFoundError:
print("No saved data found.")
return []
data = [{"name": "Alice", "roll": 101}, {"name": "Bob", "roll": 102}]
save_students(data, "students.pkl")
loaded = load_students("students.pkl")
print(loaded)
Industry Application: CSV Sales Report Generator
At companies like Shopify, Amazon, and Flipkart, backend teams use Python scripts to process daily sales CSV data โ aggregating totals per product, calculating revenue breakdowns, and generating automated summary reports that are emailed to management. These pipelines handle millions of transaction records using robust file handling and exception management.
Python
import csv
import os
from collections import defaultdict
def generate_sales_report(csv_file, output_file):
"""Read sales CSV, aggregate by product, generate report."""
product_sales = defaultdict(lambda: {"qty": 0, "revenue": 0.0})
try:
with open(csv_file, "r") as f:
reader = csv.DictReader(f)
for row in reader:
product = row["product"]
qty = int(row["quantity"])
price = float(row["price"])
product_sales[product]["qty"] += qty
product_sales[product]["revenue"] += qty * price
except FileNotFoundError:
print(f"โ Error: File '{csv_file}' not found!")
return
except (ValueError, KeyError) as e:
print(f"โ Data error: {e}")
return
# Generate report
total_revenue = sum(d["revenue"] for d in product_sales.values())
report_lines = []
report_lines.append("โ" * 50)
report_lines.append("๐ DAILY SALES SUMMARY REPORT")
report_lines.append("โ" * 50)
report_lines.append(f"{' Product':20}{'Qty':>8}{'Revenue':>15}")
report_lines.append("โ" * 50)
for product, data in sorted(product_sales.items()):
report_lines.append(
f" {product:20}{data['qty']:>8} โน{data['revenue']:>12,.2f}"
)
report_lines.append("โ" * 50)
report_lines.append(f" {'TOTAL':28} โน{total_revenue:>12,.2f}")
report_lines.append("โ" * 50)
report = "\n".join(report_lines)
print(report)
# Save report to file
with open(output_file, "w") as f:
f.write(report)
print(f"\nโ
Report saved to {output_file}")
# Demo with sample data
generate_sales_report("sales_data.csv", "daily_report.txt")
Quick Quiz โ Chapter 12
Q1. What does the file mode 'a' do in open()?
- Reads the file from the beginning
- Writes to the file, overwriting existing content
- Appends data to the end of the file without overwriting
- Opens the file in binary mode
Q2. Why is the with statement preferred for file operations?
- It makes file operations faster
- It automatically closes the file even if an exception occurs
- It allows reading and writing simultaneously
- It compresses the file automatically
Q3. In a try-except-else-finally block, when does the else clause execute?
- When an exception occurs
- Always, regardless of exceptions
- Only when no exception occurs in the try block
- Before the try block
Q4. How do you create a custom exception in Python?
- By using the error keyword
- By inheriting from the Exception class
- By importing from the exceptions module
- By decorating a function with @exception
Q5. What module is used to serialize Python objects to binary files?
- json
- pickle
- csv
- shelve
Chapter Summary
open(file, mode)โ modes:'r','w','a','r+','b'- Always use
withstatement for automatic file closing - Reading:
read(),readline(),readlines(), orfor line in f - Writing:
write(),writelines()โ must convert non-strings first osmodule:listdir(),path.exists(),makedirs(),path.join()pickle:dump()saves objects,load()restores them (binary files)try-except-else-finallyhandles exceptions gracefully
Regular Expressions & Web Scraping
Learning Objectives
- Understand regular expression syntax and metacharacters
- Use re.match(), re.search(), re.findall(), re.sub()
- Validate emails, phone numbers, and dates with regex
- Scrape web data using requests + regex
13.1 The re Module
Python's re module provides regular expression support for pattern matching in strings.
Python
import re
# re.search() โ find first match anywhere in string
result = re.search(r"\d+", "Age is 25 years")
print(result.group()) # 25
# re.match() โ match only at START of string
result = re.match(r"\d+", "25 years old")
print(result.group()) # 25
result = re.match(r"\d+", "Age is 25")
print(result) # None (no match at start)
# re.findall() โ find ALL matches
nums = re.findall(r"\d+", "I have 3 cats and 2 dogs")
print(nums) # ['3', '2']
# re.sub() โ find and replace
result = re.sub(r"\d+", "#", "Phone: 123-456-7890")
print(result) # Phone: #-#-#
13.2 Metacharacters
| Character | Meaning | Example |
|---|---|---|
. | Any character (except newline) | h.t โ hat, hot |
^ | Start of string | ^Hello |
$ | End of string | world$ |
* | 0 or more repetitions | ab*c โ ac, abc, abbc |
+ | 1 or more repetitions | ab+c โ abc, abbc |
? | 0 or 1 repetition | colou?r โ color, colour |
{n} | Exactly n repetitions | \d{3} โ 123 |
{n,m} | Between n and m repetitions | \d{2,4} โ 12, 123, 1234 |
[] | Character set | [aeiou] โ any vowel |
| | OR | cat|dog |
() | Group | (\d+)-(\d+) |
\ | Escape special character | \. โ literal dot |
13.3 Character Classes
| Class | Meaning | Equivalent |
|---|---|---|
\d | Any digit | [0-9] |
\D | Any non-digit | [^0-9] |
\w | Any word character | [a-zA-Z0-9_] |
\W | Any non-word character | [^a-zA-Z0-9_] |
\s | Any whitespace | [ \t\n\r\f\v] |
\S | Any non-whitespace | [^ \t\n\r\f\v] |
13.4 Groups and Backreferences
Python
import re
# Groups with ()
pattern = r"(\d{3})-(\d{3})-(\d{4})"
match = re.search(pattern, "Call 123-456-7890")
print(match.group()) # 123-456-7890 (full match)
print(match.group(1)) # 123 (first group)
print(match.group(2)) # 456 (second group)
print(match.group(3)) # 7890 (third group)
print(match.groups()) # ('123', '456', '7890')
13.5 Practical Examples
Python
import re
# Validate email
def is_valid_email(email):
pattern = r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"
return bool(re.match(pattern, email))
print(is_valid_email("alice@gmail.com")) # True
print(is_valid_email("invalid@")) # False
# Validate phone number (Indian: 10 digits starting with 6-9)
def is_valid_phone(phone):
pattern = r"^[6-9]\d{9}$"
return bool(re.match(pattern, phone))
print(is_valid_phone("9876543210")) # True
print(is_valid_phone("1234567890")) # False
# Validate date (DD/MM/YYYY)
def is_valid_date(date):
pattern = r"^\d{2}/\d{2}/\d{4}$"
return bool(re.match(pattern, date))
print(is_valid_date("25/12/2024")) # True
13.6 re.compile() for Reusable Patterns
Python
import re
# Compile a pattern for reuse
email_pattern = re.compile(r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}")
text = "Contact alice@gmail.com or bob@yahoo.com for info"
emails = email_pattern.findall(text)
print(emails) # ['alice@gmail.com', 'bob@yahoo.com']
# Compiled patterns are faster when used multiple times
word_pattern = re.compile(r"\b\w{5,}\b") # Words with 5+ chars
result = word_pattern.findall("The quick brown fox jumps")
print(result) # ['quick', 'brown', 'jumps']
13.7 Web Scraping with requests + re
Python
import re
# import requests # pip install requests
# Example: Extract all links from HTML
html = """
<a href="https://google.com">Google</a>
<a href="https://python.org">Python</a>
<a href="https://github.com">GitHub</a>
"""
links = re.findall(r'href="(https?://[^"]+)"', html)
print(links)
# Extract emails from text
text = "Email us at info@company.com or support@company.com"
emails = re.findall(r"[\w.+-]+@[\w-]+\.[\w.]+", text)
print(emails)
13.8 Brief BeautifulSoup Intro
Python
# pip install beautifulsoup4 requests
from bs4 import BeautifulSoup
html = "<html><body><h1>Title</h1><p>Hello</p></body></html>"
soup = BeautifulSoup(html, "html.parser")
print(soup.find("h1").text) # Title
print(soup.find("p").text) # Hello
print(soup.find_all("p")) # [<p>Hello</p>]
# Real-world: scrape a page
# import requests
# response = requests.get("https://example.com")
# soup = BeautifulSoup(response.text, "html.parser")
# for link in soup.find_all("a"):
# print(link.get("href"))
Exercises
Exercise 13.1: Write a regex to extract all hashtags from a tweet
Python
import re
tweet = "Learning #Python is fun! #coding #100DaysOfCode"
hashtags = re.findall(r"#\w+", tweet)
print(hashtags) # ['#Python', '#coding', '#100DaysOfCode']
Exercise 13.2: Write a function to mask credit card numbers (show only last 4 digits)
Python
import re
def mask_card(text):
return re.sub(r"\b(\d{4})-(\d{4})-(\d{4})-(\d{4})\b",
r"****-****-****-\4", text)
print(mask_card("Card: 1234-5678-9012-3456"))
# Card: ****-****-****-3456
Exercise 13.3: Extract all IP addresses from a log file text
Python
import re
log = """
192.168.1.1 - GET /index.html
10.0.0.5 - POST /api/data
172.16.0.100 - GET /about
"""
ips = re.findall(r"\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b", log)
print(ips) # ['192.168.1.1', '10.0.0.5', '172.16.0.100']
Industry Application: Server Log Analyzer
At companies like Cloudflare, Datadog, and Splunk, engineers use Python regex to parse massive Apache/Nginx server log files in real-time. These analyzers extract IP addresses, request URLs, HTTP status codes, and response times โ then compute error rates, identify suspicious IPs, and generate automated incident reports for the NOC team.
Python
import re
from collections import Counter
# Sample Apache-format log entries
log_data = """
192.168.1.10 - - [15/Jun/2025:10:15:30 +0530] "GET /api/users HTTP/1.1" 200 1234
10.0.0.5 - - [15/Jun/2025:10:15:31 +0530] "POST /api/login HTTP/1.1" 401 89
192.168.1.10 - - [15/Jun/2025:10:15:32 +0530] "GET /static/style.css HTTP/1.1" 200 5678
172.16.0.100 - - [15/Jun/2025:10:15:33 +0530] "GET /api/products HTTP/1.1" 500 0
10.0.0.5 - - [15/Jun/2025:10:15:34 +0530] "POST /api/login HTTP/1.1" 401 89
192.168.1.10 - - [15/Jun/2025:10:15:35 +0530] "GET /dashboard HTTP/1.1" 200 4521
172.16.0.100 - - [15/Jun/2025:10:15:36 +0530] "DELETE /api/users/5 HTTP/1.1" 403 45
"""
# Regex pattern to parse Apache log format
log_pattern = re.compile(
r'(\d+\.\d+\.\d+\.\d+)' # IP address
r'.*?"(\w+)\s+(\/\S+)\s+' # Method & URL
r'HTTP/[\d.]+" (\d{3})' # Status code
)
# Parse all log entries
entries = log_pattern.findall(log_data)
# Analyze results
status_counts = Counter(status for _, _, _, status in entries)
ip_counts = Counter(ip for ip, _, _, _ in entries)
error_entries = [(ip, method, url, code)
for ip, method, url, code in entries
if int(code) >= 400]
total = len(entries)
errors = len(error_entries)
error_rate = (errors / total) * 100 if total else 0
print("โ" * 45)
print("๐ SERVER LOG ANALYSIS REPORT")
print("โ" * 45)
print(f"Total Requests : {total}")
print(f"Error Rate : {error_rate:.1f}%")
print(f"\nStatus Breakdown:")
for code, count in sorted(status_counts.items()):
print(f" {code}: {count} requests")
print(f"\nTop IPs:")
for ip, count in ip_counts.most_common(3):
print(f" {ip}: {count} requests")
Quick Quiz โ Chapter 13
Q1. What is the difference between re.match() and re.search()?
- match() searches the entire string; search() only checks the start
- match() checks only the start; search() finds the first match anywhere
- Both are identical in behavior
- match() returns all matches; search() returns the first
Q2. Which character class matches any digit character in regex?
- \w
- \d
- \s
- \b
Q3. What does the + quantifier mean in a regex pattern?
- Match exactly one occurrence
- Match zero or more occurrences
- Match one or more occurrences
- Match zero or one occurrence
Q4. How do you access the second captured group from a regex match object m?
- m.group[2]
- m.group(2)
- m.groups[1]
- m.capture(2)
Q5. What is the advantage of using re.compile()?
- It makes the pattern case-insensitive
- It compiles the pattern once for faster reuse across multiple operations
- It automatically escapes special characters
- It returns all matches instead of one
Chapter Summary
re.match()matches at start;re.search()finds first match anywherere.findall()returns all matches as a listre.sub()replaces matched patterns- Character classes:
\d(digit),\w(word),\s(space) - Quantifiers:
*(0+),+(1+),?(0-1),{n,m} - Groups with
()capture sub-patterns; access with.group(n) re.compile()creates reusable pattern objects for better performance- Web scraping: use
requeststo fetch HTML,reorBeautifulSoupto parse
Lab Experiments
Learning Objectives
- Implement 40 complete Python programs with explanations (15 core + 25 industry)
- Cover arithmetic, number theory, string manipulation, files, and data structures
- Practice recursion, file I/O, binary files, and stack operations
This chapter contains 40 complete lab experiments โ 15 core programs covering arithmetic, number theory, recursion, file handling, binary files, and data structures, plus 25 industry-related problems from e-commerce, banking, cybersecurity, DevOps, EdTech, and more. Each experiment includes a problem statement, complete code, sample output, and key concept explanations.
Experiment 1: Arithmetic Operations
Problem: Write a program to perform all basic arithmetic operations (+, -, *, /, //, %) on two user-input numbers.
Python
# Experiment 1: Arithmetic Operations
a = float(input("Enter first number: "))
b = float(input("Enter second number: "))
print(f"Addition: {a} + {b} = {a + b}")
print(f"Subtraction: {a} - {b} = {a - b}")
print(f"Multiplication: {a} * {b} = {a * b}")
print(f"Division: {a} / {b} = {a / b}")
print(f"Floor Division: {a} // {b} = {a // b}")
print(f"Modulus: {a} % {b} = {a % b}")
print(f"Exponent: {a} ** {b} = {a ** b}")
Experiment 2: Perfect Number Checker
Problem: Check if a number is a perfect number (sum of its proper divisors equals the number). Examples: 6 (1+2+3), 28 (1+2+4+7+14).
Python
# Experiment 2: Perfect Number Checker
def is_perfect(n):
if n < 2:
return False
divisor_sum = 1
for i in range(2, int(n**0.5) + 1):
if n % i == 0:
divisor_sum += i
if i != n // i:
divisor_sum += n // i
return divisor_sum == n
num = int(input("Enter a number: "))
if is_perfect(num):
print(f"{num} is a Perfect Number")
else:
print(f"{num} is NOT a Perfect Number")
Experiment 3: Armstrong Number Checker
Problem: Check if a number is an Armstrong number (sum of each digit raised to the power of total digits equals the number). Example: 153 = 1ยณ + 5ยณ + 3ยณ.
Python
# Experiment 3: Armstrong Number Checker
def is_armstrong(n):
digits = str(n)
power = len(digits)
total = sum(int(d) ** power for d in digits)
return total == n
num = int(input("Enter a number: "))
if is_armstrong(num):
print(f"{num} is an Armstrong Number")
else:
print(f"{num} is NOT an Armstrong Number")
# Print all 3-digit Armstrong numbers
print("3-digit Armstrong numbers:", end=" ")
for i in range(100, 1000):
if is_armstrong(i):
print(i, end=" ")
Experiment 4: Factorial Calculator
Problem: Calculate the factorial of a number using an iterative approach. n! = n ร (n-1) ร (n-2) ร ... ร 1.
Python
# Experiment 4: Factorial Calculator (Iterative)
def factorial(n):
if n < 0:
return "Factorial not defined for negative numbers"
result = 1
for i in range(2, n + 1):
result *= i
return result
num = int(input("Enter a number: "))
print(f"{num}! = {factorial(num)}")
Experiment 5: Fibonacci Series
Problem: Generate the Fibonacci series up to n terms. Each number is the sum of the two preceding ones: 0, 1, 1, 2, 3, 5, 8, 13...
Python
# Experiment 5: Fibonacci Series
def fibonacci(n):
series = []
a, b = 0, 1
for _ in range(n):
series.append(a)
a, b = b, a + b
return series
n = int(input("How many terms? "))
result = fibonacci(n)
print(f"Fibonacci series ({n} terms):")
print(" โ ".join(str(x) for x in result))
Experiment 6: Palindrome Checker Using Loop
Problem: Check if a string is a palindrome (reads the same forwards and backwards) using a loop, without using slicing.
Python
# Experiment 6: Palindrome Checker (Using Loop)
def is_palindrome(s):
s = s.lower().replace(" ", "")
left = 0
right = len(s) - 1
while left < right:
if s[left] != s[right]:
return False
left += 1
right -= 1
return True
text = input("Enter a string: ")
if is_palindrome(text):
print(f"'{text}' is a Palindrome")
else:
print(f"'{text}' is NOT a Palindrome")
Experiment 7: Recursive Factorial
Problem: Calculate factorial using recursion. Base case: 0! = 1. Recursive case: n! = n ร (n-1)!
Python
# Experiment 7: Recursive Factorial
def factorial_recursive(n):
# Base case
if n == 0 or n == 1:
return 1
# Recursive case
return n * factorial_recursive(n - 1)
num = int(input("Enter a number: "))
print(f"{num}! = {factorial_recursive(num)}")
# Show the recursion trace
print(f"\nTrace: {num}! = ", end="")
print(" ร ".join(str(i) for i in range(num, 0, -1)), f"= {factorial_recursive(num)}")
Experiment 8: Read a File Line by Line
Problem: Read a text file and print its contents line by line with line numbers.
Python
# Experiment 8: Read File Line by Line
# First, create a sample file
with open("sample.txt", "w") as f:
f.write("Python is powerful\n")
f.write("It is easy to learn\n")
f.write("Practice makes perfect\n")
f.write("Keep coding every day\n")
# Read and display
print("Contents of sample.txt:")
print("=" * 30)
with open("sample.txt", "r") as f:
for line_num, line in enumerate(f, 1):
print(f"Line {line_num}: {line.strip()}")
Experiment 9: Remove Lines Containing 'a'
Problem: Read a file, remove all lines containing the letter 'a', and write the remaining lines to another file.
Python
# Experiment 9: Filter Lines Without 'a'
# Create input file
with open("input.txt", "w") as f:
f.write("apple is red\n")
f.write("sky is blue\n")
f.write("banana is yellow\n")
f.write("sun is bright\n")
f.write("cat is cute\n")
# Filter and write
with open("input.txt", "r") as fin, open("output.txt", "w") as fout:
for line in fin:
if "a" not in line.lower():
fout.write(line)
# Display result
print("Lines without 'a':")
with open("output.txt") as f:
print(f.read())
Experiment 10: Count Vowels, Consonants, Uppercase & Lowercase
Problem: Read a text file and count the number of vowels, consonants, uppercase letters, and lowercase letters.
Python
# Experiment 10: Character Analysis
with open("sample.txt", "w") as f:
f.write("Hello World! Python Programming 2024.\n")
vowels = consonants = upper = lower = 0
vowel_set = set("aeiouAEIOU")
with open("sample.txt") as f:
for char in f.read():
if char.isalpha():
if char in vowel_set:
vowels += 1
else:
consonants += 1
if char.isupper():
upper += 1
else:
lower += 1
print(f"Vowels: {vowels}")
print(f"Consonants: {consonants}")
print(f"Uppercase: {upper}")
print(f"Lowercase: {lower}")
Experiment 11: Binary File โ Student Records
Problem: Store student records (name, roll number) in a binary file using pickle, then search by roll number.
Python
# Experiment 11: Binary File with Pickle
import pickle
# Write student records
students = [
{"name": "Alice", "roll": 101},
{"name": "Bob", "roll": 102},
{"name": "Charlie", "roll": 103},
{"name": "Diana", "roll": 104},
]
with open("students.pkl", "wb") as f:
pickle.dump(students, f)
print("Records saved!")
# Search by roll number
search_roll = 102
with open("students.pkl", "rb") as f:
data = pickle.load(f)
found = False
for s in data:
if s["roll"] == search_roll:
print(f"Found: {s['name']} (Roll: {s['roll']})")
found = True
break
if not found:
print(f"Roll {search_roll} not found.")
Experiment 12: Random Dice Simulator
Problem: Simulate rolling a dice (1-6) multiple times and display the frequency of each outcome.
Python
# Experiment 12: Dice Simulator
import random
def roll_dice(n_rolls):
freq = {i: 0 for i in range(1, 7)}
for _ in range(n_rolls):
roll = random.randint(1, 6)
freq[roll] += 1
return freq
n = 1000
results = roll_dice(n)
print(f"Rolling dice {n} times:")
print("-" * 25)
for face, count in results.items():
bar = "โ" * (count // 10)
print(f" {face}: {count:4d} {bar}")
Experiment 13: Stack Using List
Problem: Implement a stack data structure using Python lists with push, pop, peek, and display operations.
Python
# Experiment 13: Stack Implementation
class Stack:
def __init__(self):
self.items = []
def push(self, item):
self.items.append(item)
print(f"Pushed: {item}")
def pop(self):
if self.is_empty():
print("Stack Underflow!")
return None
return self.items.pop()
def peek(self):
if self.is_empty():
return "Stack is empty"
return self.items[-1]
def is_empty(self):
return len(self.items) == 0
def display(self):
print("Stack:", self.items)
# Demo
s = Stack()
s.push(10)
s.push(20)
s.push(30)
s.display()
print(f"Peek: {s.peek()}")
print(f"Popped: {s.pop()}")
s.display()
Experiment 14: Phishing Email Word Frequency
Problem: Analyze a text for phishing-related keywords and display their frequency to detect potential phishing emails.
Python
# Experiment 14: Phishing Email Word Frequency
def analyze_phishing(text):
phishing_words = [
"urgent", "verify", "account", "password",
"click", "suspend", "immediately", "confirm",
"security", "update", "login", "bank",
"expire", "free", "winner", "prize"
]
words = text.lower().split()
freq = {}
for word in words:
clean = word.strip(".,!?;:\"'")
if clean in phishing_words:
freq[clean] = freq.get(clean, 0) + 1
print("Phishing Word Analysis:")
print("-" * 30)
if freq:
for word, count in sorted(freq.items(), key=lambda x: x[1], reverse=True):
print(f" {word:15s} : {count}")
score = sum(freq.values())
risk = "HIGH" if score >= 5 else "MEDIUM" if score >= 3 else "LOW"
print(f"\nRisk Level: {risk} (Score: {score})")
else:
print(" No phishing keywords detected.")
email = """URGENT! Your account has been suspended.
Click here to verify your password immediately.
Confirm your account to avoid permanent suspension.
Update your security information now."""
analyze_phishing(email)
Experiment 15: Words Separated by #
Problem: Read a text file and display all words separated by the # character.
Python
# Experiment 15: Words Separated by #
# Create sample file
with open("words.txt", "w") as f:
f.write("Python is a powerful programming language\n")
f.write("It is used for web development and data science\n")
f.write("Practice makes perfect\n")
# Read and display words separated by #
print("Words from file (separated by #):")
print("=" * 50)
with open("words.txt", "r") as f:
for line in f:
words = line.strip().split()
print("#".join(words))
Experiment 16: E-Commerce Discount Engine
Problem: Build a pricing engine used by Amazon/Flipkart โ apply tiered discounts (10% for orders >โน1000, 15% for >โน5000, 20% for >โน10000), apply coupon codes, and calculate GST at 18%.
Python
# Experiment 16: E-Commerce Discount Engine
def calculate_invoice(cart, coupon=None):
# Coupon definitions
coupons = {"SAVE10": 10, "MEGA20": 20, "FLAT500": 500}
subtotal = sum(item["price"] * item["qty"] for item in cart)
# Tiered discount
if subtotal > 10000:
tier_disc = 0.20
elif subtotal > 5000:
tier_disc = 0.15
elif subtotal > 1000:
tier_disc = 0.10
else:
tier_disc = 0
after_tier = subtotal * (1 - tier_disc)
# Apply coupon
coupon_disc = 0
if coupon and coupon in coupons:
val = coupons[coupon]
coupon_disc = val if val >= 100 else after_tier * val / 100
after_coupon = after_tier - coupon_disc
gst = after_coupon * 0.18
total = after_coupon + gst
print("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ")
print("โ E-COMMERCE INVOICE โ")
print("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ")
for item in cart:
line = item["price"] * item["qty"]
print(f" {item['name']:20s} x{item['qty']} โน{line:.2f}")
print("-" * 38)
print(f" Subtotal: โน{subtotal:.2f}")
print(f" Tier Discount ({tier_disc*100:.0f}%): -โน{subtotal*tier_disc:.2f}")
if coupon_disc:
print(f" Coupon ({coupon}): -โน{coupon_disc:.2f}")
print(f" GST (18%): +โน{gst:.2f}")
print("=" * 38)
print(f" TOTAL: โน{total:.2f}")
cart = [
{"name": "Wireless Mouse", "price": 599, "qty": 2},
{"name": "USB Hub", "price": 1299, "qty": 1},
{"name": "Keyboard", "price": 2450, "qty": 3}
]
calculate_invoice(cart, "SAVE10")
Experiment 17: Student Grade Management System
Problem: Used by universities and LMS platforms like Moodle โ input student marks for multiple subjects, calculate total/average/percentage, assign grade (A/B/C/D/F), and generate a formatted report card.
Python
# Experiment 17: Student Grade Management System
def get_grade(percentage):
if percentage >= 90: return "A+"
elif percentage >= 80: return "A"
elif percentage >= 70: return "B"
elif percentage >= 60: return "C"
elif percentage >= 50: return "D"
else: return "F"
students = {
"Ananya Sharma": {"Math": 92, "Physics": 88, "CS": 95, "English": 78},
"Rahul Verma": {"Math": 65, "Physics": 72, "CS": 80, "English": 68},
"Priya Patel": {"Math": 45, "Physics": 52, "CS": 38, "English": 55}
}
for name, marks in students.items():
total = sum(marks.values())
avg = total / len(marks)
pct = (total / (len(marks) * 100)) * 100
grade = get_grade(pct)
print(f"โโโโ Report Card: {name} โโโโ")
for sub, mark in marks.items():
bar = "โ" * (mark // 5)
print(f" {sub:10s}: {mark:3d}/100 {bar}")
print(f" Total: {total}/{len(marks)*100} Avg: {avg:.1f}")
print(f" Percentage: {pct:.1f}% Grade: {grade}")
status = "PASS" if all(m >= 40 for m in marks.values()) else "FAIL"
print(f" Status: {status}")
print()
Experiment 18: Password Strength Validator
Problem: Used by Google, Microsoft, and banks โ check password length (8+), verify it has uppercase, lowercase, digit, and special character. Rate as Weak/Medium/Strong with feedback.
Python
# Experiment 18: Password Strength Validator
def check_password(password):
checks = {
"Length (8+)": len(password) >= 8,
"Uppercase": any(c.isupper() for c in password),
"Lowercase": any(c.islower() for c in password),
"Digit": any(c.isdigit() for c in password),
"Special Char": any(c in "!@#$%^&*()-_+=<>?" for c in password)
}
score = sum(checks.values())
if score == 5: strength = "๐ข STRONG"
elif score >= 3: strength = "๐ก MEDIUM"
else: strength = "๐ด WEAK"
print(f"Password: {'*' * len(password)}")
print(f"Strength: {strength} ({score}/5)")
print("Criteria Check:")
for criterion, passed in checks.items():
icon = "โ
" if passed else "โ"
print(f" {icon} {criterion}")
passwords = ["hello", "Hello123", "Str0ng@Pass!"]
for pwd in passwords:
check_password(pwd)
print()
Experiment 19: Employee Payroll Calculator
Problem: Used by HR/payroll systems (Zoho, SAP) โ calculate gross salary from basic pay + HRA (40%) + DA (30%), deduct PF (12%), professional tax, and income tax based on slabs.
Python
# Experiment 19: Employee Payroll Calculator
def calc_income_tax(annual):
if annual <= 250000: return 0
elif annual <= 500000: return (annual - 250000) * 0.05
elif annual <= 1000000: return 12500 + (annual - 500000) * 0.20
else: return 112500 + (annual - 1000000) * 0.30
def payroll(name, basic):
hra = basic * 0.40
da = basic * 0.30
gross = basic + hra + da
pf = basic * 0.12
prof_tax = 200
annual_gross = gross * 12
income_tax = calc_income_tax(annual_gross) / 12
total_deductions = pf + prof_tax + income_tax
net = gross - total_deductions
print(f"โโโโ PAYSLIP: {name} โโโโ")
print(f" Basic Pay: โน{basic:>10,.2f}")
print(f" HRA (40%): โน{hra:>10,.2f}")
print(f" DA (30%): โน{da:>10,.2f}")
print(f" Gross Salary: โน{gross:>10,.2f}")
print(" --- Deductions ---")
print(f" PF (12%): -โน{pf:>10,.2f}")
print(f" Prof. Tax: -โน{prof_tax:>10,.2f}")
print(f" Income Tax: -โน{income_tax:>10,.2f}")
print(f" โโโโโโโโโโโโโโโโโโโโโโ")
print(f" NET SALARY: โน{net:>10,.2f}")
payroll("Vikram Singh", 45000)
print()
payroll("Neha Gupta", 75000)
Experiment 20: Inventory Stock Alert System
Problem: Used by retail chains (Walmart, BigBasket) โ manage product inventory, track stock levels, generate alerts when stock falls below reorder level, and calculate total inventory value.
Python
# Experiment 20: Inventory Stock Alert System
inventory = [
{"id": "P001", "name": "Laptop", "price": 52000, "stock": 5, "reorder": 10},
{"id": "P002", "name": "Mouse", "price": 499, "stock": 150, "reorder": 50},
{"id": "P003", "name": "Monitor", "price": 18500, "stock": 8, "reorder": 15},
{"id": "P004", "name": "Keyboard", "price": 1299, "stock": 200, "reorder": 30},
{"id": "P005", "name": "Headphones", "price": 2999, "stock": 3, "reorder": 20}
]
print("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ")
print("โ INVENTORY STOCK REPORT โ")
print("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ")
print(f"{'ID':<6} {'Product':<12} {'Price':>8} {'Stock':>6} {'Value':>12} {'Status'}")
print("-" * 60)
total_value = 0
alerts = []
for p in inventory:
value = p["price"] * p["stock"]
total_value += value
status = "๐ด LOW" if p["stock"] < p["reorder"] else "๐ข OK"
print(f"{p['id']:<6} {p['name']:<12} โน{p['price']:>7,} {p['stock']:>5} โน{value:>10,} {status}")
if p["stock"] < p["reorder"]:
alerts.append(p)
print("-" * 60)
print(f"Total Inventory Value: โน{total_value:,}")
print(f"\nโ ๏ธ REORDER ALERTS ({len(alerts)} items):")
for a in alerts:
print(f" โ {a['name']}: {a['stock']} left (min: {a['reorder']})")
Experiment 21: Banking Transaction Logger
Problem: Used by banks (SBI, HDFC) โ implement a simple bank account with deposit/withdraw/balance check, log all transactions with timestamps, and handle insufficient funds.
Python
# Experiment 21: Banking Transaction Logger
from datetime import datetime
class BankAccount:
def __init__(self, holder, balance=0):
self.holder = holder
self.balance = balance
self.transactions = []
def _log(self, txn_type, amount, status):
ts = datetime.now().strftime("%Y-%m-%d %H:%M")
self.transactions.append({
"time": ts, "type": txn_type,
"amount": amount, "status": status,
"balance": self.balance
})
def deposit(self, amount):
self.balance += amount
self._log("CREDIT", amount, "SUCCESS")
print(f"โ
Deposited โน{amount:,.2f} | Balance: โน{self.balance:,.2f}")
def withdraw(self, amount):
if amount > self.balance:
self._log("DEBIT", amount, "FAILED")
print(f"โ Insufficient funds! Balance: โน{self.balance:,.2f}")
else:
self.balance -= amount
self._log("DEBIT", amount, "SUCCESS")
print(f"โ
Withdrawn โน{amount:,.2f} | Balance: โน{self.balance:,.2f}")
def statement(self):
print(f"\n๐ Statement for: {self.holder}")
print(f"{'Time':<18} {'Type':<8} {'Amount':>10} {'Status':<8} {'Balance':>10}")
print("-" * 60)
for t in self.transactions:
print(f"{t['time']:<18} {t['type']:<8} โน{t['amount']:>8,.2f} {t['status']:<8} โน{t['balance']:>8,.2f}")
acc = BankAccount("Raj Kumar", 10000)
acc.deposit(25000)
acc.withdraw(8000)
acc.withdraw(50000)
acc.deposit(15000)
acc.statement()
Experiment 22: CSV Data Analyzer (Sales Report)
Problem: Used by business analytics teams โ read sales data (product, quantity, price), calculate revenue per product, find top-selling product, and generate summary statistics.
Python
# Experiment 22: CSV Data Analyzer (Sales Report)
# Simulated CSV sales data
sales_data = [
["Product", "Quantity", "Unit Price"],
["Laptop", "15", "52000"],
["Mouse", "120", "499"],
["Monitor", "30", "18500"],
["Keyboard", "85", "1299"],
["Headphones", "60", "2999"],
["Webcam", "45", "3500"]
]
print("โโโ SALES REVENUE REPORT โโโ\n")
print(f"{'Product':<12} {'Qty':>5} {'Unit Price':>10} {'Revenue':>12}")
print("-" * 45)
revenues = {}
for row in sales_data[1:]:
product, qty, price = row[0], int(row[1]), int(row[2])
revenue = qty * price
revenues[product] = revenue
print(f"{product:<12} {qty:>5} โน{price:>9,} โน{revenue:>11,}")
print("-" * 45)
total = sum(revenues.values())
print(f"{'TOTAL':<12} {'':>5} {'':>10} โน{total:>11,}")
top = max(revenues, key=revenues.get)
low = min(revenues, key=revenues.get)
print(f"\n๐ Summary:")
print(f" Top Seller: {top} (โน{revenues[top]:,})")
print(f" Lowest Seller: {low} (โน{revenues[low]:,})")
print(f" Avg Revenue: โน{total // len(revenues):,}")
Experiment 23: Contact Book Application (CRUD)
Problem: Used as basis for CRM systems โ Create, Read, Update, Delete contacts stored in a dictionary. Search by name or phone. Save to file and load on startup.
Python
# Experiment 23: Contact Book Application (CRUD)
class ContactBook:
def __init__(self):
self.contacts = {}
def add(self, name, phone, email):
self.contacts[name] = {"phone": phone, "email": email}
print(f"โ
Added: {name}")
def update(self, name, phone=None, email=None):
if name in self.contacts:
if phone: self.contacts[name]["phone"] = phone
if email: self.contacts[name]["email"] = email
print(f"โ
Updated: {name}")
else:
print(f"โ Contact '{name}' not found.")
def delete(self, name):
if name in self.contacts:
del self.contacts[name]
print(f"๐๏ธ Deleted: {name}")
else:
print(f"โ Contact '{name}' not found.")
def search(self, query):
results = {k: v for k, v in self.contacts.items()
if query.lower() in k.lower() or query in v["phone"]}
return results
def display(self):
print(f"\n๐ Contact Book ({len(self.contacts)} contacts)")
print(f"{'Name':<18} {'Phone':<15} {'Email'}")
print("-" * 50)
for name, info in sorted(self.contacts.items()):
print(f"{name:<18} {info['phone']:<15} {info['email']}")
book = ContactBook()
book.add("Amit Shah", "9876543210", "amit@email.com")
book.add("Priya Nair", "8765432109", "priya@email.com")
book.add("Karan Mehta", "7654321098", "karan@email.com")
book.update("Amit Shah", phone="9999999999")
book.display()
print(f"\n๐ Search 'Priya': {book.search('Priya')}")
book.delete("Karan Mehta")
book.display()
Experiment 24: Matrix Operations Calculator
Problem: Used in data science and ML (NumPy internally) โ add, subtract, multiply matrices using nested lists. Transpose a matrix. Calculate determinant of a 2x2 matrix.
Python
# Experiment 24: Matrix Operations Calculator
def print_matrix(matrix, label=""):
if label: print(f" {label}:")
for row in matrix:
print(" โ", " ".join(f"{x:>4}" for x in row), "โ")
def mat_add(a, b):
return [[a[i][j] + b[i][j] for j in range(len(a[0]))] for i in range(len(a))]
def mat_multiply(a, b):
rows_a, cols_b = len(a), len(b[0])
result = [[0] * cols_b for _ in range(rows_a)]
for i in range(rows_a):
for j in range(cols_b):
for k in range(len(b)):
result[i][j] += a[i][k] * b[k][j]
return result
def transpose(m):
return [[m[j][i] for j in range(len(m))] for i in range(len(m[0]))]
def det_2x2(m):
return m[0][0] * m[1][1] - m[0][1] * m[1][0]
A = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
B = [[9, 8, 7], [6, 5, 4], [3, 2, 1]]
print("โโโ MATRIX OPERATIONS โโโ")
print_matrix(A, "Matrix A")
print_matrix(B, "Matrix B")
print_matrix(mat_add(A, B), "A + B")
print_matrix(mat_multiply(A, B), "A ร B")
print_matrix(transpose(A), "Transpose(A)")
D = [[3, 8], [4, 6]]
print(f" Determinant of [[3,8],[4,6]] = {det_2x2(D)}")
Experiment 25: Word Frequency Counter (Text Analytics)
Problem: Used by SEO tools (Ahrefs, SEMrush) and NLP pipelines โ read a paragraph, count word frequencies, find top 5 most common words, and ignore common stop words.
Python
# Experiment 25: Word Frequency Counter (Text Analytics)
def word_frequency(text):
stop_words = {"the", "is", "a", "an", "in", "to", "of",
"and", "for", "it", "on", "with", "as", "are",
"that", "this", "by", "be", "at", "or"}
words = text.lower().split()
freq = {}
for word in words:
clean = word.strip(".,!?;:\"'()-")
if clean and clean not in stop_words:
freq[clean] = freq.get(clean, 0) + 1
sorted_freq = sorted(freq.items(), key=lambda x: x[1], reverse=True)
print("โโโ WORD FREQUENCY ANALYSIS โโโ")
print(f"Total words: {len(words)} | Unique: {len(freq)} | Stop words removed\n")
print("Top 5 Words:")
for word, count in sorted_freq[:5]:
bar = "โ" * (count * 3)
print(f" {word:<15} {count:>3} {bar}")
text = """Python is a powerful programming language used for web development,
data science, and machine learning. Python provides extensive libraries
for data analysis. Machine learning with Python is growing rapidly.
Python developers use Python for automation and data processing."""
word_frequency(text)
Experiment 26: Simple Calculator with Error Handling
Problem: Production-grade calculator โ handles division by zero, invalid input, supports +, -, *, /, **, sqrt. Uses try-except for robust error handling and keeps running until user quits.
Python
# Experiment 26: Simple Calculator with Error Handling
import math
def calculator():
print("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ")
print("โ SCIENTIFIC CALCULATOR โ")
print("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ")
print(" Operations: + - * / ** sqrt")
print(" Type 'quit' to exit\n")
history = []
# Simulated inputs for demonstration
inputs = [("+", 15, 25), ("/", 10, 0),
("**", 2, 10), ("sqrt", 144, None)]
for op, a, b in inputs:
try:
if op == "sqrt":
if a < 0:
raise ValueError("Cannot sqrt negative number")
result = math.sqrt(a)
expr = f"โ{a}"
elif op == "/" and b == 0:
raise ZeroDivisionError("Division by zero!")
else:
result = eval(f"{a} {op} {b}")
expr = f"{a} {op} {b}"
print(f" โ
{expr} = {result}")
history.append(f"{expr} = {result}")
except ZeroDivisionError as e:
print(f" โ Error: {e}")
except ValueError as e:
print(f" โ Error: {e}")
print(f"\n๐ History ({len(history)} calculations):")
for h in history:
print(f" โ {h}")
calculator()
Experiment 27: File Encryption/Decryption (Caesar Cipher)
Problem: Used in cybersecurity education โ read text from a file, encrypt using Caesar cipher with a key, write encrypted text to a new file. Decrypt back and verify.
Python
# Experiment 27: File Encryption/Decryption (Caesar Cipher)
def caesar_encrypt(text, key):
result = ""
for ch in text:
if ch.isalpha():
base = ord('A') if ch.isupper() else ord('a')
result += chr(((ord(ch) - base + key) % 26) + base)
else:
result += ch
return result
def caesar_decrypt(text, key):
return caesar_encrypt(text, -key)
# Original message
original = "Python Programming is Powerful and Secure!"
key = 7
# Encrypt
encrypted = caesar_encrypt(original, key)
# Decrypt
decrypted = caesar_decrypt(encrypted, key)
print("โโโ CAESAR CIPHER โโโ")
print(f" Key: {key}")
print(f" Original: {original}")
print(f" Encrypted: {encrypted}")
print(f" Decrypted: {decrypted}")
print(f" Verified: {'โ
Match!' if original == decrypted else 'โ Mismatch!'}")
# Simulate file write/read
print("\n๐ File Operations:")
print(f" โ Written encrypted text to 'encrypted.txt'")
print(f" โ Read and decrypted from 'encrypted.txt'")
print(f" โ Verification: PASSED")
Experiment 28: Number System Converter
Problem: Used in computer architecture courses and embedded systems โ convert between decimal, binary, octal, and hexadecimal. Show step-by-step conversion process.
Python
# Experiment 28: Number System Converter
def manual_decimal_to_binary(n):
"""Convert decimal to binary with steps."""
steps = []
num = n
if n == 0: return "0", ["0 รท 2 = 0 remainder 0"]
while num > 0:
steps.append(f"{num:>5} รท 2 = {num//2:>5} remainder {num%2}")
num //= 2
binary = bin(n)[2:]
return binary, steps
def convert_all(decimal):
print(f"โโโ NUMBER SYSTEM CONVERTER โโโ")
print(f" Input (Decimal): {decimal}\n")
binary, steps = manual_decimal_to_binary(decimal)
print(" Step-by-step Decimal โ Binary:")
for s in steps:
print(f" {s}")
print(f" Read remainders bottom-up: {binary}\n")
print(f" โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ")
print(f" โ Decimal: {decimal:<16} โ")
print(f" โ Binary: {bin(decimal):<16} โ")
print(f" โ Octal: {oct(decimal):<16} โ")
print(f" โ Hexadecimal: {hex(decimal):<16} โ")
print(f" โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ")
# Reverse conversions
print(f"\n Reverse Verification:")
print(f" Binary '{bin(decimal)}' โ {int(bin(decimal), 2)}")
print(f" Octal '{oct(decimal)}' โ {int(oct(decimal), 8)}")
print(f" Hex '{hex(decimal)}' โ {int(hex(decimal), 16)}")
convert_all(156)
Experiment 29: URL Shortener (Hash-Based)
Problem: Used by Bitly, TinyURL โ generate short codes from long URLs using hashing. Store mapping in a dictionary. Lookup short code to get original URL.
Python
# Experiment 29: URL Shortener (Hash-Based)
import hashlib
url_store = {}
def shorten_url(long_url, base="https://short.ly/"):
"""Generate a short code from a long URL using MD5 hash."""
hash_obj = hashlib.md5(long_url.encode())
short_code = hash_obj.hexdigest()[:7]
short_url = base + short_code
url_store[short_code] = long_url
return short_url
def resolve_url(short_code):
"""Lookup original URL from short code."""
return url_store.get(short_code, "URL not found!")
# Test with sample URLs
urls = [
"https://www.example.com/very/long/path/to/resource/page",
"https://docs.python.org/3/library/hashlib.html",
"https://www.github.com/user/repository/issues/42"
]
print("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ")
print("โ URL SHORTENER SERVICE โ")
print("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ")
for url in urls:
short = shorten_url(url)
print(f"Long : {url}")
print(f"Short : {short}")
print("-" * 45)
# Resolve a short code
test_code = list(url_store.keys())[0]
print(f"\nResolving '{test_code}': {resolve_url(test_code)}")
print(f"Resolving 'invalid': {resolve_url('invalid')}")
Experiment 30: Tic-Tac-Toe Game
Problem: Classic game development exercise โ 3ร3 board using nested list, two players (X/O), check win conditions (rows, columns, diagonals), detect draw.
Python
# Experiment 30: Tic-Tac-Toe Game
def create_board():
return [[" "] * 3 for _ in range(3)]
def display_board(board):
print(" 0 1 2")
for i, row in enumerate(board):
print(f"{i} " + " | ".join(row))
if i < 2:
print(" -----------")
def check_winner(board, player):
# Check rows, columns, and diagonals
for i in range(3):
if all(board[i][j] == player for j in range(3)):
return True
if all(board[j][i] == player for j in range(3)):
return True
if all(board[i][i] == player for i in range(3)):
return True
if all(board[i][2 - i] == player for i in range(3)):
return True
return False
def is_draw(board):
return all(board[i][j] != " " for i in range(3) for j in range(3))
# Simulate a game
board = create_board()
moves = [(0,0,"X"), (1,1,"O"), (0,1,"X"),
(2,0,"O"), (0,2,"X")]
print("๐ฎ Tic-Tac-Toe Game Simulation")
print("=" * 30)
for r, c, p in moves:
board[r][c] = p
print(f"\n{p} plays at ({r},{c}):")
display_board(board)
if check_winner(board, p):
print(f"\n๐ Player {p} wins!")
break
if is_draw(board):
print("\n๐ค It's a draw!")
Experiment 31: Email Validator using Regex
Problem: Used by every web form โ validate email format using regex. Check for valid domain extensions. Test with valid and invalid examples.
Python
# Experiment 31: Email Validator using Regex
import re
def validate_email(email):
"""Validate email using regex pattern."""
pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
if re.match(pattern, email):
domain = email.split("@")[1]
valid_tlds = [".com", ".org", ".edu", ".net", ".in", ".io"]
if any(domain.endswith(tld) for tld in valid_tlds):
return "โ
Valid", "Accepted"
return "โ ๏ธ Valid format", "Unknown TLD"
return "โ Invalid", "Bad format"
# Test with various emails
test_emails = [
"user@example.com",
"student.name@university.edu",
"dev+tag@startup.io",
"invalid@",
"no-at-sign.com",
"spaces in@email.com",
"valid@domain.xyz",
]
print("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ")
print("โ EMAIL VALIDATION REPORT โ")
print("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ")
for email in test_emails:
status, reason = validate_email(email)
print(f" {email:35s} {status} ({reason})")
Experiment 32: Simple REST API Data Processor
Problem: Used in backend development โ simulate processing JSON API responses. Parse nested JSON-like dictionaries, extract specific fields, transform data.
Python
# Experiment 32: Simple REST API Data Processor
# Simulated API response (nested JSON-like dict)
api_response = {
"status": "success",
"count": 3,
"data": [
{"id": 101, "name": "Alice", "role": "Developer",
"skills": ["Python", "Django"], "rating": 4.8},
{"id": 102, "name": "Bob", "role": "Designer",
"skills": ["Figma", "CSS"], "rating": 4.5},
{"id": 103, "name": "Charlie", "role": "Developer",
"skills": ["Java", "Spring", "Python"], "rating": 4.6}
]
}
print("๐ก API Response Processor")
print("=" * 45)
print(f"Status: {api_response['status']} | Records: {api_response['count']}")
print("-" * 45)
# Extract developers only
devs = [u for u in api_response["data"] if u["role"] == "Developer"]
print(f"\n๐จโ๐ป Developers ({len(devs)}):")
for d in devs:
print(f" {d['name']:10s} โญ {d['rating']} Skills: {', '.join(d['skills'])}")
# Aggregate all unique skills
all_skills = set(s for u in api_response["data"] for s in u["skills"])
print(f"\n๐ ๏ธ All Unique Skills: {', '.join(sorted(all_skills))}")
# Average rating
avg = sum(u["rating"] for u in api_response["data"]) / api_response["count"]
print(f"๐ Average Rating: {avg:.2f}")
Experiment 33: Attendance Tracker System
Problem: Used by schools and colleges (ERP systems) โ track student attendance for multiple subjects, calculate attendance percentage, identify students below 75% threshold.
Python
# Experiment 33: Attendance Tracker System
attendance = {
"Rahul": {"Math": (28, 30), "Physics": (20, 30), "CS": (29, 30)},
"Sneha": {"Math": (25, 30), "Physics": (27, 30), "CS": (26, 30)},
"Amit": {"Math": (18, 30), "Physics": (22, 30), "CS": (20, 30)},
"Priya": {"Math": (30, 30), "Physics": (28, 30), "CS": (27, 30)},
}
def calc_percentage(attended, total):
return (attended / total) * 100
print("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ")
print("โ ATTENDANCE TRACKER REPORT โ")
print("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ")
below_threshold = []
for student, subjects in attendance.items():
total_att = sum(a for a, t in subjects.values())
total_cls = sum(t for a, t in subjects.values())
overall = calc_percentage(total_att, total_cls)
flag = "โ ๏ธ" if overall < 75 else "โ
"
print(f"\n{flag} {student} (Overall: {overall:.1f}%)")
for sub, (att, tot) in subjects.items():
pct = calc_percentage(att, tot)
bar = "โ" * int(pct // 5) + "โ" * (20 - int(pct // 5))
print(f" {sub:10s} {att}/{tot} {bar} {pct:.0f}%")
if overall < 75:
below_threshold.append((student, overall))
print(f"\n{'='*55}")
print(f"โ ๏ธ Students below 75% attendance:")
for name, pct in below_threshold:
print(f" โ {name}: {pct:.1f}%")
Experiment 34: Electricity Bill Calculator
Problem: Used by power utilities (BESCOM, TNEB) โ calculate electricity bill based on tiered slab rates (0-100 units: โน3.50, 101-300: โน5.75, 300+: โน8.00), add fixed charges and tax.
Python
# Experiment 34: Electricity Bill Calculator
def calculate_bill(units, name="Customer"):
"""Calculate electricity bill with tiered slab rates."""
fixed_charge = 50
tax_rate = 0.05 # 5% tax
if units <= 100:
amount = units * 3.50
slab = "Slab 1 (โน3.50/unit)"
elif units <= 300:
amount = 100 * 3.50 + (units - 100) * 5.75
slab = "Slab 1 + Slab 2 (โน5.75/unit)"
else:
amount = 100 * 3.50 + 200 * 5.75 + (units - 300) * 8.00
slab = "Slab 1 + 2 + 3 (โน8.00/unit)"
tax = amount * tax_rate
total = amount + fixed_charge + tax
print("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ")
print(f"โ โก ELECTRICITY BILL โ")
print("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค")
print(f"โ Customer : {name:20s} โ")
print(f"โ Units : {units:<20d} โ")
print(f"โ Slab : {slab:<20s} โ")
print("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค")
print(f"โ Energy Charge : โน{amount:10.2f} โ")
print(f"โ Fixed Charge : โน{fixed_charge:10.2f} โ")
print(f"โ Tax (5%) : โน{tax:10.2f} โ")
print("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค")
print(f"โ TOTAL : โน{total:10.2f} โ")
print("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ")
calculate_bill(85, "Ramesh Kumar")
print()
calculate_bill(450, "Sunita Devi")
Experiment 35: Library Book Management System
Problem: Used by library management software โ track books (title, author, ISBN), issue and return books, check availability, maintain member records using class-based design.
Python
# Experiment 35: Library Book Management System
class Book:
def __init__(self, title, author, isbn):
self.title = title
self.author = author
self.isbn = isbn
self.is_available = True
self.issued_to = None
class Library:
def __init__(self, name):
self.name = name
self.books = []
def add_book(self, book):
self.books.append(book)
def issue_book(self, isbn, member):
for book in self.books:
if book.isbn == isbn and book.is_available:
book.is_available = False
book.issued_to = member
return f"โ
'{book.title}' issued to {member}"
return "โ Book not available"
def return_book(self, isbn):
for book in self.books:
if book.isbn == isbn and not book.is_available:
book.is_available = True
member = book.issued_to
book.issued_to = None
return f"โ
'{book.title}' returned by {member}"
return "โ Invalid return"
def display_catalog(self):
print(f"\n๐ {self.name} โ Catalog")
print(f"{'Title':25s} {'Author':20s} {'Status':12s}")
print("โ" * 60)
for b in self.books:
status = "Available" if b.is_available else f"Issuedโ{b.issued_to}"
print(f" {b.title:23s} {b.author:20s} {status}")
# Setup library
lib = Library("City Central Library")
lib.add_book(Book("Python Crash Course", "Eric Matthes", "978-1"))
lib.add_book(Book("Clean Code", "Robert Martin", "978-2"))
lib.add_book(Book("Design Patterns", "GoF", "978-3"))
lib.display_catalog()
print("\n" + lib.issue_book("978-1", "Arun"))
print(lib.issue_book("978-2", "Meera"))
lib.display_catalog()
print("\n" + lib.return_book("978-1"))
lib.display_catalog()
Experiment 36: Temperature Converter & Weather Analyzer
Problem: Used by weather apps (AccuWeather) โ convert between Celsius/Fahrenheit/Kelvin, analyze weekly temperature data (min, max, average), identify hot and cold days.
Python
# Experiment 36: Temperature Converter & Weather Analyzer
def c_to_f(c): return c * 9/5 + 32
def c_to_k(c): return c + 273.15
def f_to_c(f): return (f - 32) * 5/9
# Weekly temperature data (Celsius)
days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
temps_c = [32, 35, 28, 40, 38, 25, 30]
print("๐ค๏ธ WEEKLY WEATHER REPORT")
print("=" * 55)
print(f"{'Day':5s} {'ยฐC':>6s} {'ยฐF':>8s} {'K':>10s} Condition")
print("-" * 55)
for day, tc in zip(days, temps_c):
tf = c_to_f(tc)
tk = c_to_k(tc)
if tc >= 38:
cond = "๐ฅ Hot"
elif tc <= 26:
cond = "โ๏ธ Cool"
else:
cond = "โ๏ธ Warm"
print(f" {day:3s} {tc:5.1f} {tf:7.1f} {tk:8.2f} {cond}")
print("-" * 55)
print(f" Min: {min(temps_c)}ยฐC ({days[temps_c.index(min(temps_c))]})")
print(f" Max: {max(temps_c)}ยฐC ({days[temps_c.index(max(temps_c))]})")
print(f" Avg: {sum(temps_c)/len(temps_c):.1f}ยฐC")
hot_days = sum(1 for t in temps_c if t >= 38)
print(f" Hot Days (โฅ38ยฐC): {hot_days}")
Experiment 37: Quiz Application with Scoring
Problem: Used by EdTech platforms (Byju's, Unacademy) โ store questions with options and correct answers, present quiz to user, track score, show results with percentage.
Python
# Experiment 37: Quiz Application with Scoring
questions = [
{"q": "What is the output of 2**3?",
"options": ["6", "8", "9", "5"], "answer": 2},
{"q": "Which data type is mutable?",
"options": ["tuple", "str", "list", "int"], "answer": 3},
{"q": "What does len() return for 'Hello'?",
"options": ["4", "5", "6", "Error"], "answer": 2},
{"q": "Which keyword starts a function?",
"options": ["func", "define", "def", "function"], "answer": 3},
{"q": "What is 10 // 3?",
"options": ["3.33", "3", "4", "1"], "answer": 2},
]
# Simulate quiz with pre-set answers
user_answers = [2, 3, 1, 3, 2] # Simulated user input
score = 0
print("๐ง PYTHON QUIZ APPLICATION")
print("=" * 50)
for i, q in enumerate(questions, 1):
print(f"\nQ{i}: {q['q']}")
for j, opt in enumerate(q["options"], 1):
print(f" {j}. {opt}")
ans = user_answers[i - 1]
correct = q["answer"]
if ans == correct:
print(f" Your answer: {ans} โ
Correct!")
score += 1
else:
print(f" Your answer: {ans} โ Wrong! (Correct: {correct})")
pct = (score / len(questions)) * 100
grade = "๐ Excellent" if pct >= 80 else "๐ Good" if pct >= 60 else "๐ Needs Practice"
print(f"\n{'='*50}")
print(f"Score: {score}/{len(questions)} ({pct:.0f}%) {grade}")
Experiment 38: Sorting Algorithm Visualizer (Comparison)
Problem: Used in CS education โ implement Bubble Sort and Selection Sort, count comparisons and swaps, compare performance on the same data.
Python
# Experiment 38: Sorting Algorithm Visualizer
def bubble_sort(arr):
"""Bubble Sort with comparison and swap counters."""
a = arr.copy()
comparisons = swaps = 0
n = len(a)
for i in range(n - 1):
for j in range(n - i - 1):
comparisons += 1
if a[j] > a[j + 1]:
a[j], a[j + 1] = a[j + 1], a[j]
swaps += 1
return a, comparisons, swaps
def selection_sort(arr):
"""Selection Sort with comparison and swap counters."""
a = arr.copy()
comparisons = swaps = 0
n = len(a)
for i in range(n - 1):
min_idx = i
for j in range(i + 1, n):
comparisons += 1
if a[j] < a[min_idx]:
min_idx = j
if min_idx != i:
a[i], a[min_idx] = a[min_idx], a[i]
swaps += 1
return a, comparisons, swaps
data = [64, 34, 25, 12, 22, 11, 90, 45]
print("๐ SORTING ALGORITHM COMPARISON")
print("=" * 45)
print(f"Original: {data}")
b_sorted, b_comp, b_swap = bubble_sort(data)
s_sorted, s_comp, s_swap = selection_sort(data)
print(f"\n{'Metric':20s} {'Bubble':>10s} {'Selection':>10s}")
print("-" * 42)
print(f"{'Comparisons':20s} {b_comp:>10d} {s_comp:>10d}")
print(f"{'Swaps':20s} {b_swap:>10d} {s_swap:>10d}")
print(f"{'Result':20s} {str(b_sorted):>10s}")
winner = "Bubble" if b_swap < s_swap else "Selection"
print(f"\n๐ Fewer swaps: {winner} Sort")
Experiment 39: Log File Word Cloud Generator
Problem: Used by analytics dashboards โ read a text file, count word frequencies excluding stop words, display top 10 words as a text-based bar chart.
Python
# Experiment 39: Log File Word Cloud Generator
# Simulated log content (instead of file read)
log_text = """ERROR connection timeout to database server
WARNING disk usage high on production server
ERROR failed to authenticate user request
INFO server started successfully on port 8080
ERROR database connection refused retry attempt
WARNING memory usage exceeded threshold on server
INFO deployment completed successfully for app
ERROR timeout waiting for response from API server
WARNING high CPU usage detected on production node
INFO backup completed successfully for database
ERROR authentication failed invalid credentials
INFO server health check passed successfully"""
stop_words = {"to", "on", "for", "from", "the", "a", "an", "is"}
# Count word frequencies
word_count = {}
for word in log_text.lower().split():
if word not in stop_words and len(word) > 2:
word_count[word] = word_count.get(word, 0) + 1
# Sort and get top 10
top_words = sorted(word_count.items(), key=lambda x: x[1], reverse=True)[:10]
max_count = top_words[0][1]
print("๐ LOG FILE WORD FREQUENCY ANALYSIS")
print("=" * 50)
print(f"Total unique words: {len(word_count)}")
print(f"\nTop 10 Words (Bar Chart):")
print("-" * 50)
for word, count in top_words:
bar_len = int((count / max_count) * 25)
bar = "โ" * bar_len
print(f" {word:15s} โ{bar:25s}โ {count}")
Experiment 40: Student Database with Binary Search
Problem: Used in database systems โ store sorted student records, implement binary search by roll number, compare with linear search performance (number of comparisons).
Python
# Experiment 40: Student Database with Binary Search
students = [
{"roll": 101, "name": "Aisha Khan", "marks": 88},
{"roll": 105, "name": "Deepak Sharma", "marks": 76},
{"roll": 112, "name": "Kavya Nair", "marks": 92},
{"roll": 118, "name": "Mohan Reddy", "marks": 65},
{"roll": 124, "name": "Pooja Gupta", "marks": 81},
{"roll": 130, "name": "Ravi Patel", "marks": 95},
{"roll": 137, "name": "Sneha Iyer", "marks": 70},
{"roll": 145, "name": "Vikram Singh", "marks": 84},
]
def binary_search(records, target_roll):
"""Binary search by roll number."""
low, high = 0, len(records) - 1
comparisons = 0
while low <= high:
mid = (low + high) // 2
comparisons += 1
if records[mid]["roll"] == target_roll:
return records[mid], comparisons
elif records[mid]["roll"] < target_roll:
low = mid + 1
else:
high = mid - 1
return None, comparisons
def linear_search(records, target_roll):
"""Linear search for comparison."""
comparisons = 0
for rec in records:
comparisons += 1
if rec["roll"] == target_roll:
return rec, comparisons
return None, comparisons
print("๐ STUDENT DATABASE โ SEARCH COMPARISON")
print("=" * 50)
search_rolls = [130, 105, 145, 999]
for roll in search_rolls:
b_result, b_comp = binary_search(students, roll)
l_result, l_comp = linear_search(students, roll)
status = f"Found: {b_result['name']} (Marks: {b_result['marks']})" \
if b_result else "Not Found"
print(f"\nRoll #{roll}: {status}")
print(f" Binary Search : {b_comp} comparisons")
print(f" Linear Search : {l_comp} comparisons")
speedup = l_comp / b_comp if b_comp > 0 else 0
print(f" Speedup : {speedup:.1f}x faster (binary)")
print(f"\n{'='*50}")
print(f"Database size: {len(students)} records")
print(f"Max binary comparisons: {len(students).bit_length()}")
print(f"Max linear comparisons: {len(students)}")
Industry Application: DevOps Automation Script
At companies like Netflix, Google, and Amazon, Site Reliability Engineers (SREs) use Python automation scripts to monitor system resources, perform scheduled backups, and trigger alerts when critical thresholds are exceeded โ such as disk usage exceeding 80%. These scripts integrate with monitoring dashboards like Grafana and PagerDuty.
Python
import os
import shutil
import platform
from datetime import datetime
def check_disk_usage(path="/", threshold=80):
"""Check disk usage and alert if above threshold."""
total, used, free = shutil.disk_usage(path)
percent_used = (used / total) * 100
status = "๐ด CRITICAL" if percent_used > threshold else "๐ข OK"
return {
"total_gb": round(total / (2**30), 2),
"used_gb": round(used / (2**30), 2),
"free_gb": round(free / (2**30), 2),
"percent": round(percent_used, 1),
"status": status
}
def backup_files(src_dir, backup_dir):
"""Create timestamped backup of important files."""
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
backup_path = os.path.join(backup_dir, f"backup_{timestamp}")
os.makedirs(backup_path, exist_ok=True)
count = 0
for f in os.listdir(src_dir):
if f.endswith((".py", ".conf", ".log")):
shutil.copy2(os.path.join(src_dir, f), backup_path)
count += 1
return f"{count} files backed up to {backup_path}"
def system_health_report():
"""Generate comprehensive system health report."""
print("โ" * 50)
print("๐ง DEVOPS SYSTEM HEALTH REPORT")
print("โ" * 50)
print(f"Host : {platform.node()}")
print(f"OS : {platform.system()} {platform.release()}")
print(f"Time : {datetime.now().strftime('%Y-%m-%d %H:%M')}")
disk = check_disk_usage()
print(f"Disk : {disk['used_gb']}GB / {disk['total_gb']}GB ({disk['percent']}%)")
print(f"Status : {disk['status']}")
if disk["percent"] > 80:
print("โ ๏ธ ALERT: Disk usage critical! Send notification.")
print("โ" * 50)
system_health_report()
Quick Quiz โ Chapter 14
Q1. What does shutil.disk_usage() return?
- Only free space
- A tuple of (total, used, free) bytes
- Disk percentage only
- A dictionary of disk stats
Q2. What is the output of [x**2 for x in range(5)]?
- [1, 4, 9, 16, 25]
- [0, 1, 4, 9, 16]
- [0, 2, 4, 6, 8]
- [1, 2, 3, 4, 5]
Q3. Which keyword is used to handle exceptions in Python?
- catch
- handle
- except
- error
Q4. What does the os.makedirs() function do?
- Creates a single directory
- Creates nested directories recursively
- Deletes directories
- Lists directory contents
Q5. In OOP, what does super().__init__() do?
- Creates a new class
- Calls the parent class constructor
- Deletes the current object
- Returns a static method
Chapter Summary
- Exp 1-3: Arithmetic, perfect numbers, Armstrong numbers โ core number operations
- Exp 4-5: Factorial and Fibonacci โ iterative algorithms with loops
- Exp 6-7: Palindrome checker and recursive factorial โ string/recursion problems
- Exp 8-10: File reading, filtering, and character analysis โ text file I/O
- Exp 11-13: Binary files (pickle), dice simulator, stack โ data structures & randomness
- Exp 14-15: Phishing word frequency & word separator โ real-world text processing
- Exp 16-19: E-commerce discount engine, student grades, password validator, payroll โ industry applications
- Exp 20-23: Inventory alerts, banking transactions, CSV analytics, contact book โ CRUD & file systems
- Exp 24-28: Matrix operations, word frequency, calculator, Caesar cipher, number converter โ algorithms & security
- Exp 29-33: URL shortener, Tic-Tac-Toe, email validator, REST API, attendance tracker โ web & systems
- Exp 34-37: Electricity bill, library management, weather analyzer, quiz app โ domain-specific systems
- Exp 38-40: Sorting comparison, word cloud generator, binary search โ CS fundamentals & performance
๐ Congratulations!
You've completed the Python Programming course. You now have the skills to write Python programs for any application โ from simple scripts to object-oriented systems with file handling and web scraping.
ยฉ 2025 EduArtha โ Python Programming Complete Course