🐍 Python For Cybersecurity
By Gurjot Singh Saini | 09 Jan 2022 | (0 Reviews)
Suggest Improvement on Python for Cybersecurity — Click here
Python is a powerful yet beginner-friendly programming language known for its clear syntax and wide range of real-world applications. In this module, you’ll learn what Python is, why it’s popular, how to install it, and where it’s used in everyday technology.
🐍 Python – Beginner’s Introduction
This module explains what Python is, why it is popular, how to install it, and where it is used in real life. The explanations are beginner-friendly with examples, alerts, tables, and diagrams.
1.0 History of Python (How It Started)
📖 The Story Behind Python
Python was created by Guido van Rossum in December 1989 while working at the Centrum Wiskunde & Informatica (CWI) in the Netherlands. He started the project during Christmas holidays as a hobby project!
Guido wanted to build a programming language that was:
- Simple & Readable – Easy to understand, like plain English
- Powerful – Could handle complex tasks
- Fun to Use – Not boring like some other languages
- Open Source – Free for everyone to use and improve
Fun Fact!
Python is NOT named after the snake 🐍. It was inspired by the British comedy show "Monty Python's Flying Circus"!
What Guido Wanted
- Replace ABC language (which was too complex)
- Fix problems in C (memory management issues)
- Better than Perl (which was hard to read)
- Easy for beginners but powerful for experts
Key Design Principles
- Beautiful is better than ugly – Clean code
- Explicit is better than implicit – Clear code
- Simple is better than complex – Easy to learn
- Readability counts – Code should be easy to read
📜 Complete Timeline of Python
| Year | Version | Major Highlights | Key Features Added |
|---|---|---|---|
| 1989 | Start | Guido starts working on Python during Christmas holidays | Initial planning and design |
| 1991 | Python 1.0 | First public release at CWI in Netherlands | Basic data types: str, list, dict, modules, exception handling |
| 1994 | Python 1.4 | Lambda, map, filter, reduce functions added | Functional programming features |
| 2000 | Python 2.0 | Major upgrade with new features | List comprehensions, garbage collection, Unicode support |
| 2001 | Python 2.2 | Unification of types and classes | New-style classes, generators, properties |
| 2005 | Python 2.5 | with statement introduced | Context managers, conditional expressions |
| 2008 | Python 3.0 | Major Breaking Change! | Print as function, Unicode strings, new division, removed old features |
| 2010 | Python 3.3 | Migration from Python 2 begins | Yield from, u'unicode' syntax, exception chaining |
| 2015 | Python 3.5 | Async/await keywords added | Asynchronous programming support, matrix multiplication (@) |
| 2018 | Python 3.7 | Data classes introduced | dataclass decorator, postponed evaluation of annotations |
| 2020 | Python 2 EOL | Python 2 support ended - Use Python 3 only! | End of Life for Python 2 series |
| 2021 | Python 3.10 | Pattern matching added | match-case statements, better error messages |
| 2022 | Python 3.11 | Up to 60% faster performance | Exception groups, exception notes, faster startup |
| 2023 | Python 3.12 | Latest stable version | More f-string features, improved error messages |
| Today | Python 3.x | Used everywhere - AI, Web, Apps, Games, Cybersecurity | Thousands of libraries, huge community support |
🌟 Why Python Became So Popular
Easy to Learn
Simple syntax like English - perfect for beginners
Huge Community
Millions of developers, endless tutorials and help
Powerful Libraries
AI: TensorFlow, Web: Django, Data: Pandas
Cross-Platform
Works on Windows, Mac, Linux, even phones!
Open Source
Free to use, modify, and distribute
Versatile
Web, AI, Games, Apps, Automation - everything!
Python is Used For:
- AI & Machine Learning
- Web Development
- Data Science
- Cybersecurity
- Game Development
- Automation
- App Development
- Cloud Computing
Companies Using Python:
- Spotify
- Netflix
- Amazon
- Microsoft
- Uber
⚠️ IMPORTANT: Python 2 is DEAD!
Python 2 officially ended support on January 1, 2020. No more updates, security fixes, or bug patches. Always use Python 3 for all new projects!
Current Python Version
Latest stable version: Python 3.13 (released October 2024)
Always download from the official website: python.org
1.1 What is Python? (Beginner-friendly explanation)
Python is a high-level, simple, and powerful programming language used for web development, automation, AI, cybersecurity, data science, and more.
📌 Key Points
- ✔ Beginner-friendly & readable syntax
- ✔ Works on Windows, Linux, and Mac
- ✔ Huge community & libraries
- ✔ Used in AI, ML, Cybersecurity, Web Dev, Automation
🆚 Python vs Other Languages (Quick Comparison)
| Language | Difficulty | Speed | Main Use |
|---|---|---|---|
| Python | Very Easy | Medium | AI, ML, Automation, Cybersecurity |
| C | Hard | Very Fast | System programming |
| Java | Medium | Fast | Enterprise applications |
| JavaScript | Easy | Fast | Web Frontend & Backend |
1.2 Features of Python (Simple, Powerful & Flexible)
Python is popular because it is flexible and easy to use. Let’s understand Python’s main features.
-
Readable & Simple Syntax
Python looks like English → easy to learn.
-
Platform Independent
Works on Windows, Mac, Linux without changes.
-
Huge Libraries
AI, ML, Automation, Web → all possible with ready-made libraries.
-
Object-Oriented
Supports classes, objects, inheritance, etc.
-
Open Source
Free to use forever!
1.3 How to Install Python & Write Your First Program
1 Step 1: Download Python
2 Step 2: Install Python
For Windows:
✓ Wait for "Setup was successful" message
For Mac:
✓ Follow the installer instructions
✓ Click "Continue" and "Install"
For Linux:
✓ Type:
sudo apt install python3 (Ubuntu/Debian)✓ Type:
sudo dnf install python3 (Fedora)
On Mac/Linux, use
python3 command instead of python
3 Step 3: Verify Installation
Open Command Prompt (Windows) or Terminal (Mac/Linux)
Type this command:
python --version (Windows)python3 --version (Mac/Linux)
You should see: Python 3.x.x
Also Check PIP
PIP installs Python packages. Check it with:
pip --version (Windows)pip3 --version (Mac/Linux)
Shows pip version number
🐍 Your First Python Program
Method 1: Interactive Mode
Type python or python3 in terminal, then:
>>> print("Hello, Python!")Hello, Python!>>> exit() (to quit)
Method 2: Create a Script
Create a file called hello.py with:
print("Hello, Python!")
Run it:
python hello.py (Windows)python3 hello.py (Mac/Linux)
'python' not recognized |
On Windows: You forgot to check "Add Python to PATH". Reinstall and check that box. |
command not found |
On Mac/Linux: Try python3 instead |
- Download: python.org/downloads
- Docs: docs.python.org
- VS Code: code.visualstudio.com
🔧 Try These Simple Examples:
print(2 + 3 * 4) → 14
name = "Alex"print(f"Hello, {name}")
input("Your name: ")print("Nice to meet you!")
📚 What to Learn Next:
1.4 Python IDEs (Which one should beginners use?)
Python can be written in many editors. Here are the best ones:
| IDE / Editor | Difficulty | Best For |
|---|---|---|
| VS Code | Easy | Everyone (Coding, Web, AI) |
| PyCharm | Medium | Big Python Projects |
| Jupyter Notebook | Very Easy | Data Science & ML |
| IDLE | Very Easy | Beginners |
1.5 Real-World Uses of Python (From Web Dev to AI)
Python is everywhere. Here are the most popular real-world uses:
- 🤖 Artificial Intelligence
- 📊 Data Science & Data Analysis
- 🕸 Web Development (Django, Flask)
- 🔐 Cybersecurity & Automation
- ⚙️ DevOps & Scripting
- 📱 App Development
- 🧪 Machine Learning
🎓 Module 01 : Introduction Successfully Completed
You have successfully completed this module of Python for Cybersecurity.
Keep building your expertise step by step — Learn Next Module →
⚖️ Comparing Python with Other Languages
This module explains how Python differs from C, C++, Java, and JavaScript. You will understand their speed, use cases, syntax difficulty, and which one is best for beginners.
2.1 Python vs C – Speed, Purpose & Code Simplicity
C is a **low-level, powerful, fast language**, while Python is **high-level and easy**. Both are useful but built for different purposes.
📌 Key Differences
| Feature | Python | C |
|---|---|---|
| Difficulty | Very Easy | Hard |
| Execution Speed | Slow | Very Fast |
| Memory Management | Automatic | Manual |
| Use Case | AI, Web, Automation | OS, embedded systems |
| Syntax | Readable | Complex |
🧪 Example Comparison
Python:
print("Hello")C:
#include <stdio.h>
int main() {
printf("Hello");
}
2.2 Python vs C++ — Object-Oriented & Performance Differences
C++ is powerful for games and high-performance apps, whereas Python is great for rapid development.
📌 Comparison Table
| Feature | Python | C++ |
|---|---|---|
| Speed | Medium | Very Fast |
| Memory Control | Automatic | Manual |
| OOP Support | Easy to Implement | Very Advanced |
| Use Cases | AI, Data Science | Games, Browsers, High-performance apps |
| Syntax | Simple | Complex |
2.3 Python vs Java – Ease of Use & Application Areas
Java is widely used in enterprise development, while Python dominates AI and automation.
🔍 Quick Comparison
| Feature | Python | Java |
|---|---|---|
| Typing | Dynamic | Static |
| Speed | Slower | Faster |
| Syntax | Short & Easy | Lengthy |
| Main Use | AI, ML, Scripts | Enterprise, Android apps |
2.4 Python vs JavaScript – Web, Backend & Scripting
Python
"General-purpose language for everything"
- Best for AI, Machine Learning, Data Science
- Backend development (Django, Flask)
- Automation & Scripting
- Scientific computing & Research
- Desktop applications
JavaScript
"The language of the web browser"
- Frontend websites & web apps (React, Vue, Angular)
- Backend with Node.js
- Mobile apps (React Native)
- Desktop apps (Electron)
- Interactive web elements
📊 Complete Feature Comparison
| Feature | Python | JavaScript |
|---|---|---|
| 🎯 Primary Area | AI, Backend, Automation, Data Science | Web Frontend & Backend, Interactive Websites |
| 🌐 Browser Support | ❌ No (Can't run directly in browser) | ✅ Yes (Runs in every browser) |
| 📚 Ease of Learning | Very Easy - Clean, readable syntax | Easy - Simple for basic tasks |
| 📝 Syntax Style | Uses indentation (spaces/tabs) Example: if x > 0:
|
Uses curly braces {} Example: if (x > 0) {
|
| ⚙️ Execution | Interpreted (runs line by line) | Interpreted (Just-in-Time compiled) |
| 🔤 Typing | Dynamic typing (variable types can change) | Dynamic typing (similar to Python) |
| 🚀 Popular Frameworks |
Django (Full-stack) Flask (Lightweight) FastAPI (High performance) PyTorch/TensorFlow (AI/ML) |
React (Frontend) Vue.js (Frontend) Angular (Frontend) Node.js (Backend) Express.js (Backend) |
| ⚡ Performance | Slower for CPU-intensive tasks (but has optimized libraries) | Fast in browsers, V8 engine is highly optimized |
| 📱 Mobile Development | Limited (Kivy, BeeWare) | Strong (React Native, Ionic) |
| 💻 Desktop Apps | Yes (Tkinter, PyQt, PySide) | Yes (Electron, NW.js) |
| 🎮 Game Development | Pygame, Panda3D (limited) | Phaser, Three.js (web games) |
| 🧠 AI & Machine Learning | 🏆 Best choice - TensorFlow, PyTorch, Scikit-learn | Limited (TensorFlow.js, ML5.js) |
| 📊 Data Science | 🏆 Excellent - Pandas, NumPy, Matplotlib | Limited (D3.js for visualization only) |
| 🔄 Concurrency | Multi-threading (limited), AsyncIO for async tasks | Single-threaded with async callbacks, Promises |
| 📦 Package Manager | pip, conda | npm, yarn |
| 👥 Community Size | Huge (especially in academia, research, data science) | Massive (largest in web development) |
| 🏢 Companies Using | Google, Facebook, Netflix, Spotify, NASA | Google, Facebook, Microsoft, Uber, Airbnb |
| 📈 Learning Curve | Gentle - Great for beginners | Moderate - Easy start, complex for advanced patterns |
| 💼 Job Market | High demand in AI, Data Science, Backend | Very high demand in Web Development (Frontend + Backend) |
| 💰 Average Salary | $90,000 - $130,000 (AI/ML specialists earn more) | $85,000 - $120,000 (varies by framework) |
🔍 Same Task in Both Languages
# Simple function
def greet(name):
return f"Hello, {name}!"
# List comprehension
numbers = [1, 2, 3, 4, 5]
squares = [n**2 for n in numbers]
# Dictionary
person = {
"name": "Alice",
"age": 30,
"city": "New York"
}
# If statement
if person["age"] >= 18:
print("Adult")
# Loop
for n in numbers:
print(n)
print(greet("Python"))
// Simple function
function greet(name) {
return `Hello, ${name}!`;
}
// Array map
const numbers = [1, 2, 3, 4, 5];
const squares = numbers.map(n => n ** 2);
// Object
const person = {
name: "Alice",
age: 30,
city: "New York"
};
// If statement
if (person.age >= 18) {
console.log("Adult");
}
// Loop
for (let n of numbers) {
console.log(n);
}
console.log(greet("JavaScript"));
- Extremely readable and beginner-friendly
- Dominates AI, ML, and Data Science
- Great for scientific computing
- Extensive libraries for everything
- Perfect for automation scripts
- Strong in academia and research
- Only language that runs natively in browsers
- Full-stack development with Node.js
- Huge ecosystem (npm, millions of packages)
- Real-time applications (chat, games)
- Cross-platform mobile apps (React Native)
- Desktop apps with Electron
- Slower than compiled languages
- Not suitable for mobile apps
- Can't run in browsers
- Global Interpreter Lock (GIL) limits threading
- Memory intensive
- Can be unpredictable (type coercion issues)
- Callback hell (though Promises help)
- Not ideal for CPU-intensive tasks
- Security issues (XSS vulnerabilities)
- Rapid changes can be overwhelming
⚖️ When to Choose Which?
✅ Choose Python When:
- You're building AI/Machine Learning applications
- You need data analysis and visualization
- You're doing scientific computing or research
- You want to write automation scripts
- You're building backend APIs (Django/Flask)
- You're teaching programming to beginners
- You need to process text/files (scripting)
✅ Choose JavaScript When:
- You're building websites (frontend)
- You need interactive web elements
- You want to build mobile apps (React Native)
- You're creating real-time applications (chat, games)
- You want full-stack with one language
- You're building browser extensions
- You need cross-platform desktop apps (Electron)
🌟 Modern Trend: Using Both Together
Many modern applications use BOTH languages:
- Python → Backend API (Django/Flask)
- JavaScript → Frontend (React/Vue)
- Example: Netflix uses Python for backend, JS for frontend
- Python → Data processing/ML
- JavaScript → Data visualization
- Example: YouTube uses Python for backend, JS for player
- 🔥 AI/ML Boom (ChatGPT, TensorFlow)
- 📊 Data Science explosion
- 🤖 Automation & Scripting
- 🎓 Top choice in education
- 📈 Fastest growing language since 2020
- 🌐 Still the only browser language
- 📱 React Native for mobile
- ⚡ Node.js for backend
- 🖥️ Electron for desktop apps
- 📈 Most used language on GitHub
📌 Quick Summary
Python = AI + Data + Backend + Automation
JavaScript = Web Frontend + Full-stack + Mobile Apps
2.5 Which Language Should You Learn First?
If you are a beginner, Python is the best starting point. It builds strong logic skills and is used almost everywhere.
🎓 Recommended Learning Order
- 1️⃣ Start with Python → Easy & powerful
- 2️⃣ Learn JavaScript → Web development
- 3️⃣ Learn C/C++ → Improve speed & logic
🎓 Module 02 : Comparisons of Python with Other Languages Successfully Completed
You have successfully completed this module of Python for Cybersecurity.
Keep building your expertise step by step — Learn Next Module →
🔤 Python Variables & Data Types
This module explains variables, naming rules, basic data types, mutability, and how to check data types easily. These concepts are the foundation of Python programming.
3.1 What is a Variable?
A variable is like a labeled container in computer memory where Python stores data. Think of it as a storage box with a name.
x = 10, Python creates a box named
'x' and puts the number 10 inside it.
📌 Real-Life Analogy
- 1 Water bottle = Variable
- 2 Water inside = Value
- 3 Bottle label = Variable name
- 4 Refilling water = Changing value
🍼 Empty bottle → bottle = ""
💧 Fill water → bottle = "water"
🧃 Change to juice → bottle = "juice"
🏷️ Label "My Bottle" → variable name
🐍 Python Examples
age = 25
price = 99.99
quantity = 10
Storing whole numbers and decimals
name = "Rahul"
city = 'Patna'
message = "Hello Python"
Storing words and sentences
is_student = True
has_job = False
passed_exam = True
Storing yes/no values
fruits = ["apple", "banana", "mango"]
marks = [85, 90, 78, 92]
mixed = ["Rahul", 25, True]
empty_list = []
Collection of items (ordered, changeable)
days = ("Mon", "Tue", "Wed")
colors = ("red", "green", "blue")
point = (10, 20)
Fixed collection (unchangeable)
student = {
"name": "Amit",
"age": 20,
"city": "Patna"
}
Key-value pairs (dict)
⚠️ Important Variable Rules
| Rule | ✅ Correct | ❌ Incorrect |
|---|---|---|
| Must start with letter or underscore | name, _age |
1name, @name |
| Can contain letters, numbers, underscore | user_name, age25 |
user-name, first name |
| Case-sensitive | Name ≠ name (different variables) |
|
| No Python keywords | my_class |
class, if, for, while |
🔄 Variables Can Change
x = 10 # x is number
print(x) # Output: 10
x = "Hello" # Now x is text (same variable!)
print(x) # Output: Hello
x = True # Now x is boolean
print(x) # Output: True
Python is dynamically-typed - variables can change type anytime!
📦 Multiple Variables
Assign same value to multiple:
x = y = z = 100
Assign different values in one line:
name, age, city = "Rahul", 25, "Patna"
📌 Quick Summary
✅ Variable = named container for storing data
✅ Created with = sign: name = value
✅ Can hold any type: numbers, text, true/false
✅ Value can change anytime
✅ Variable names should be meaningful
3.2 Rules & Naming Conventions
Variable names must follow Python rules. Think of it like naming a file on your computer – some names work, some don't!
✅ Allowed
-
✓
Start with letter:
name, age, total -
✓
Start with underscore:
_hidden, _private -
✓
Include numbers:
age1, score2, player3 -
✓
Use underscore:
user_name, total_price -
✓
Mix uppercase/lowercase:
UserName, TotalPrice
❌ Not Allowed
-
✗
Start with number:
1name, 2score -
✗
Use spaces:
user name, total price -
✗
Use special symbols:
user$name, total-price -
✗
Python keywords:
if, else, for, while, class -
✗
Only numbers:
123, 999
name = "Rahul" ✅
Name = "Rahul" ✅ (different variable!)
NAME = "Rahul" ✅ (also different)
name, Name, and NAME are all different variables!
🌟 Best Practices (How Experts Do It)
| Style | Example | When to Use |
|---|---|---|
| snake_case (most common) | user_name, total_price, is_student |
For regular variables and functions |
| PascalCase | StudentInfo, BankAccount, CarModel |
For class names |
| UPPER_CASE | PI, MAX_SIZE, DEFAULT_COLOR |
For constants (values that never change) |
| _single_underscore | _private, _internal |
"Private" variables (by convention) |
💡 Golden Rule: Meaningful Names
Bad: tp (what is this?)
Good: total_price (clear meaning!)
Bad: d (duration? distance? date?)
Good: duration_in_days (crystal clear!)
Quick Checklist
✅ Start with letter or _
✅ Use letters, numbers, _
✅ Be descriptive
❌ No spaces
❌ No special symbols
❌ No Python keywords
3.3 Basic Data Types with Real-Life Examples
Python has several built-in data types. Think of them as different containers for different kinds of information - just like you use different containers for water, rice, or books in real life!
| Data Type | Description | Real-Life Example | Python Example |
|---|---|---|---|
| int | Whole numbers (no decimals) | Number of students → 30 | students = 30 |
| float | Decimal numbers | Temperature → 36.5 | temp = 36.5 |
| str | Text (string) | Name → "Amit" | name = "Amit" |
| bool | True or False | Is light ON? → True | light_on = True |
| list | Ordered collection (changeable) | Shopping list → ["apple", "milk"] | items = ["apple", "milk"] |
| tuple | Ordered collection (unchangeable) | Days of week → ("Mon", "Tue") | days = ("Mon", "Tue") |
| dict | Key-value pairs | Student details → {"name": "Amit", "age": 20} | student = {"name": "Amit", "age": 20} |
🐍 Deep Dive into Each Data Type
What it is: Whole numbers without decimals. Unlimited precision (can be very large).
Real-life: Counting: 30 students, -5°C temperature, 2025 year, 1 crore population.
🔢 Arithmetic Operations
| Operator | Meaning | Example | Result |
|---|---|---|---|
+ | Addition | 10 + 3 | 13 |
- | Subtraction | 10 - 3 | 7 |
* | Multiplication | 10 * 3 | 30 |
/ | Division (returns float) | 10 / 3 | 3.333... |
// | Floor division | 10 // 3 | 3 |
% | Modulo (remainder) | 10 % 3 | 1 |
** | Exponent | 2 ** 4 | 16 |
🔄 Type Conversion Functions
| Function | Description | Example | Result |
|---|---|---|---|
int() | Convert to integer | int("123") | 123 |
int() | Truncates float | int(45.67) | 45 |
int() | From boolean | int(True) | 1 |
📊 Built-in Functions for Integers
| Function | Description | Example | Result |
|---|---|---|---|
abs() | Absolute value | abs(-10) | 10 |
pow() | Power (same as **) | pow(2, 3) | 8 |
divmod() | Returns (quotient, remainder) | divmod(10, 3) | (3, 1) |
bin() | Binary representation | bin(5) | '0b101' |
oct() | Octal representation | oct(10) | '0o12' |
hex() | Hexadecimal representation | hex(255) | '0xff' |
🔢 Counting and Number Properties
# Count digits in an integer
num = 12345
digit_count = len(str(num)) # 5
# Check if number is even/odd
n = 7
is_even = n % 2 == 0 # False
is_odd = n % 2 == 1 # True
# Get list of digits
digits = [int(d) for d in str(12345)] # [1, 2, 3, 4, 5]
# Bitwise operations (for advanced)
a = 5 # binary 101
b = 3 # binary 011
print(a & b) # AND → 1 (001)
print(a | b) # OR → 7 (111)
print(a ^ b) # XOR → 6 (110)
print(~a) # NOT → -6 (two's complement)
print(a << 1) # Left shift → 10 (1010)
print(a >> 1) # Right shift → 2 (10)
# Large integers (unlimited precision)
big = 10**100
print(big) # 1 followed by 100 zeros
What it is: Numbers with decimal points. Used for precise measurements.
Real-life: Temperature 36.6°C, price ₹99.99, weight 2.5 kg, distance 3.14 km.
⚖️ Float Operations
| Operator | Description | Example | Result |
|---|---|---|---|
+ - * / | Basic arithmetic | 10.5 + 3.2 | 13.7 |
// | Floor division | 10.5 // 3.2 | 3.0 |
% | Modulo (remainder) | 10.5 % 3.2 | 0.9 |
** | Exponent | 2.5 ** 2 | 6.25 |
🎯 Rounding and Precision Methods
| Method/Function | Description | Example | Result |
|---|---|---|---|
round() | Round to nearest | round(3.14159, 2) | 3.14 |
math.floor() | Round down | math.floor(3.9) | 3 |
math.ceil() | Round up | math.ceil(3.1) | 4 |
float.is_integer() | Check if no fractional part | (5.0).is_integer() | True |
🔄 Type Conversion
| Function | Description | Example | Result |
|---|---|---|---|
float() | Convert to float | float("99.99") | 99.99 |
float() | From integer | float(10) | 10.0 |
float() | From boolean | float(True) | 1.0 |
📐 Scientific Notation and Special Values
# Scientific notation
big = 1.5e6 # 1500000.0 (1.5 × 10⁶)
small = 2e-3 # 0.002
# Special float values
import math
print(float('inf')) # Infinity
print(float('-inf')) # -Infinity
print(float('nan')) # NaN (Not a Number)
print(math.isnan(float('nan'))) # True
# Precision issues
print(0.1 + 0.2) # 0.30000000000000004 (binary floating point)
# Solution for exact decimal calculations
from decimal import Decimal
print(Decimal('0.1') + Decimal('0.2')) # 0.3 (exact)
# Formatting floats for display
pi = 3.14159265
print(f"{pi:.2f}") # 3.14
print(f"{pi:.3f}") # 3.142
print(f"{pi:.0f}") # 3
What it is: Sequence of characters (text). Immutable (cannot be changed after creation).
Real-life: Name, address, email, paragraph, password, JSON data.
📝 Common String Methods
| Method | Description | Example | Result |
|---|---|---|---|
.upper() | Uppercase | "hello".upper() | "HELLO" |
.lower() | Lowercase | "HELLO".lower() | "hello" |
.capitalize() | First letter uppercase | "python".capitalize() | "Python" |
.title() | Each word capitalized | "hello world".title() | "Hello World" |
.strip() | Remove whitespace | " hi ".strip() | "hi" |
.lstrip() | Remove left whitespace | " hi".lstrip() | "hi" |
.rstrip() | Remove right whitespace | "hi ".rstrip() | "hi" |
.split() | Split into list | "a,b,c".split(",") | ["a","b","c"] |
.join() | Join list into string | "-".join(["1","2"]) | "1-2" |
.replace() | Replace substring | "hi".replace("i","ello") | "hello" |
.find() | Find index of substring | "hello".find("e") | 1 |
.rfind() | Find from right | "hello".rfind("l") | 3 |
.count() | Count occurrences | "abca".count("a") | 2 |
.startswith() | Check start | "Python".startswith("Py") | True |
.endswith() | Check end | "Python".endswith("on") | True |
.isalpha() | All letters? | "abc".isalpha() | True |
.isdigit() | All digits? | "123".isdigit() | True |
.isalnum() | Letters/digits only? | "abc123".isalnum() | True |
.isspace() | All whitespace? | " ".isspace() | True |
✂️ Slicing and Indexing
text = "Python Programming"
# Index: 0 1 2 3 4 5 ...
print(text[0]) # P
print(text[-1]) # g (last character)
print(text[0:6]) # Python
print(text[7:]) # Programming
print(text[:6]) # Python
print(text[::-1]) # gnimmargorP nohtyP (reverse)
# Step slicing
print(text[::2]) # Pto rgamn (every 2nd character)
print(text[1::2]) # yhnPormig (every 2nd starting from 1)
📏 String Length and Counting
s = "Hello, World!"
print(len(s)) # 13 (including comma and space)
# Count specific characters
print(s.count('l')) # 3
print(s.count('o')) # 2
# Count words
words = s.split()
print(len(words)) # 2 (["Hello,", "World!"])
# Count vowels
vowels = sum(1 for char in s.lower() if char in 'aeiou')
print(vowels) # 3
# Character frequency
from collections import Counter
print(Counter(s.lower())) # Counter({'l': 3, 'o': 2, ...})
🔤 String Formatting
name = "Amit"
age = 25
height = 5.75
# f-strings (Python 3.6+)
print(f"My name is {name}, I am {age} years old and {height}ft tall.")
# .format() method
print("My name is {}, I am {} years old.".format(name, age))
# % formatting (older style)
print("My name is %s, I am %d years old." % (name, age))
# Alignment and padding
print(f"{name:<10}|") # Left align (10 width)
print(f"{name:>10}|") # Right align
print(f"{name:^10}|") # Center
print(f"{age:05d}") # Pad with zeros: 00025
What it is: Represents True or False. Foundation of logic and decision making.
Real-life: Light ON/OFF, answer Yes/No, condition met/not met, flag raised/down.
⚡ Boolean Operations
| Operator | Meaning | Example | Result |
|---|---|---|---|
and | Both True | True and False | False |
or | At least one True | True or False | True |
not | Inverts | not True | False |
== | Equal to | 5 == 5 | True |
!= | Not equal | 5 != 3 | True |
> | Greater than | 5 > 3 | True |
< | Less than | 5 < 3 | False |
>= | Greater or equal | 5 >= 5 | True |
<= | Less or equal | 5 <= 3 | False |
🧠 Truthy and Falsy Values
In Python, all values have an inherent boolean truth value:
| Falsy Values (evaluate to False) | Truthy Values (evaluate to True) |
|---|---|
None | True |
False | Non-empty strings: "hello" |
0, 0.0 | Non-zero numbers: 1, -1, 3.14 |
Empty sequences: "", [], (), {} | Non-empty sequences: [1,2], (1,), {"a":1} |
🔄 Conversion to Boolean
# Using bool() constructor
print(bool(0)) # False
print(bool(1)) # True
print(bool("")) # False
print(bool("Hello")) # True
print(bool([])) # False
print(bool([1,2])) # True
print(bool(None)) # False
# In conditions (automatic conversion)
if "hello": # Truthy
print("This runs")
if 0: # Falsy
print("This never runs")
🔢 Boolean as Integers
# Boolean is a subclass of int (True=1, False=0)
print(True + True) # 2
print(True * 5) # 5
print(False * 10) # 0
print(True == 1) # True
print(False == 0) # True
# Counting True values in a list
flags = [True, False, True, True, False]
print(sum(flags)) # 3 (counts True as 1)
# Using boolean in arithmetic
total = sum([x > 5 for x in [3, 7, 2, 8, 1]])
print(total) # 2 (numbers greater than 5)
# Boolean methods
print(True & False) # False (bitwise AND)
print(True | False) # True (bitwise OR)
print(True ^ True) # False (XOR)
What it is: An ordered, changeable (mutable) collection. Can hold mixed types. Lists are like a dynamic to-do list you can modify anytime.
➕ Adding Items to a List
| Method | Description | Example | Result |
|---|---|---|---|
.append(item) |
Adds item to the end | fruits.append("kiwi") |
["apple","banana","kiwi"] |
.insert(index, item) |
Inserts item at a specific position | fruits.insert(1, "mango") |
["apple","mango","banana"] |
.extend([items]) |
Adds multiple items to the end | fruits.extend(["grape","berry"]) |
["apple","banana","grape","berry"] |
+ operator |
Concatenates two lists | new = [1,2] + [3,4] |
[1,2,3,4] |
# Real-life shopping list
cart = ["milk", "bread"]
cart.append("eggs") # ['milk', 'bread', 'eggs']
cart.insert(1, "butter") # ['milk', 'butter', 'bread', 'eggs']
cart.extend(["juice", "cereal"]) # ['milk', 'butter', 'bread', 'eggs', 'juice', 'cereal']
❌ Deleting Items from a List
| Method | Description | Example | Result |
|---|---|---|---|
.remove(item) |
Removes first occurrence of item | fruits.remove("banana") |
["apple","mango"] |
.pop(index) |
Removes & returns item at index (default last) | fruits.pop(0) |
removes first item |
del list[index] |
Deletes item by index | del fruits[1] |
removes second item |
.clear() |
Empties the entire list | fruits.clear() |
[] |
colors = ["red", "green", "blue", "green"]
colors.remove("green") # removes first 'green' → ['red', 'blue', 'green']
last = colors.pop() # removes & returns 'green' → colors now ['red', 'blue']
del colors[0] # removes 'red' → colors now ['blue']
colors.clear() # []
✂️ Slicing: start, stop, step
Syntax: list[start:stop:step]
| Parameter | Description | Default |
|---|---|---|
start | Index to begin slice (inclusive) | 0 (beginning) |
stop | Index to end slice (exclusive) | end of list |
step | Increment between indices | 1 |
🔹 Basic Slicing
fruits = ["🍎apple", "🍌banana", "🥭mango", "🍊orange", "🍇grapes"]
# indices: 0 1 2 3 4
fruits[1:3] # ['🍌banana', '🥭mango']
fruits[:3] # ['🍎apple', '🍌banana', '🥭mango']
fruits[2:] # ['🥭mango', '🍊orange', '🍇grapes']
fruits[-3:-1] # ['🥭mango', '🍊orange']
🔹 Using step
fruits[::2] # ['🍎apple', '🥭mango', '🍇grapes']
fruits[1:4:2] # ['🍌banana', '🍊orange']
fruits[::-1] # REVERSE
fruits[4:1:-1] # ['🍇grapes', '🍊orange', '🥭mango']
🔄 Sorting and Reversing Lists
| Method | Description | Example | Result |
|---|---|---|---|
.sort() |
Sorts list in-place (ascending) | nums = [3,1,4]; nums.sort() |
[1,3,4] |
.sort(reverse=True) |
Sorts list in-place (descending) | nums.sort(reverse=True) |
[4,3,1] |
.reverse() |
Reverses list in-place | nums.reverse() |
[1,3,4] → [4,3,1] |
sorted(list) |
Returns new sorted list (original unchanged) | new = sorted([3,1,4]) |
[1,3,4] |
reversed(list) |
Returns reverse iterator (use list() to convert) | list(reversed([1,2,3])) |
[3,2,1] |
# In-place sorting
numbers = [5, 2, 8, 1, 9]
numbers.sort()
print(numbers) # [1, 2, 5, 8, 9]
# Descending sort
numbers.sort(reverse=True)
print(numbers) # [9, 8, 5, 2, 1]
# Reverse (not sorted, just reverses order)
fruits = ["banana", "apple", "cherry"]
fruits.reverse()
print(fruits) # ['cherry', 'apple', 'banana']
# Get new sorted list without modifying original
original = [3, 1, 4]
sorted_copy = sorted(original)
print(original) # [3, 1, 4] (unchanged)
print(sorted_copy) # [1, 3, 4]
# Custom sorting with key
words = ["apple", "banana", "kiwi", "strawberry"]
words.sort(key=len) # sort by length
print(words) # ['kiwi', 'apple', 'banana', 'strawberry']
# Sort by last character
words.sort(key=lambda x: x[-1])
print(words) # ['banana', 'apple', 'kiwi', 'strawberry']
📋 Copying Lists (Important!)
| Method | Description | Example | Notes |
|---|---|---|---|
= assignment |
Creates reference, not copy | list2 = list1 |
Changes to list2 affect list1! |
.copy() |
Shallow copy | list2 = list1.copy() |
Independent copy (1 level) |
list[:] |
Shallow copy via slicing | list2 = list1[:] |
Same as .copy() |
list() |
Shallow copy via constructor | list2 = list(list1) |
Same as .copy() |
copy.deepcopy() |
Deep copy (nested lists) | import copy; list2 = copy.deepcopy(list1) |
For lists containing other lists |
# Assignment (WRONG way to copy - creates reference)
list1 = [1, 2, 3]
list2 = list1 # This is NOT a copy!
list2.append(4)
print(list1) # [1, 2, 3, 4] (original changed!)
# Correct shallow copy methods
list1 = [1, 2, 3]
list2 = list1.copy() # Method 1: .copy()
list3 = list1[:] # Method 2: slicing
list4 = list(list1) # Method 3: constructor
list2.append(4)
list3.append(5)
list4.append(6)
print(list1) # [1, 2, 3] (original unchanged)
print(list2) # [1, 2, 3, 4]
print(list3) # [1, 2, 3, 5]
print(list4) # [1, 2, 3, 6]
# Deep copy for nested lists
nested = [[1, 2], [3, 4]]
shallow = nested.copy() # Shallow copy
deep = copy.deepcopy(nested) # Deep copy (requires import copy)
shallow[0].append(99)
print(nested) # [[1, 2, 99], [3, 4]] (original changed!)
print(deep) # [[1, 2], [3, 4]] (original unchanged)
🔗 Joining and Combining Lists
| Method | Description | Example | Result |
|---|---|---|---|
+ operator |
Concatenates lists | [1,2] + [3,4] |
[1,2,3,4] |
.extend() |
Adds all items from another list | list1.extend([3,4]) |
Modifies list1 |
* operator |
Repeats list | [1,2] * 3 |
[1,2,1,2,1,2] |
list(itertools.chain()) |
Chain multiple lists | list(chain([1,2], [3,4])) |
[1,2,3,4] |
# Using + operator (creates new list)
a = [1, 2, 3]
b = [4, 5, 6]
c = a + b
print(c) # [1, 2, 3, 4, 5, 6]
# Using extend (modifies original)
a.extend(b)
print(a) # [1, 2, 3, 4, 5, 6]
# Repeat list
zeros = [0] * 5
print(zeros) # [0, 0, 0, 0, 0]
# Join list of strings into one string
words = ["Hello", "World"]
sentence = " ".join(words)
print(sentence) # "Hello World"
# Flatten list of lists
matrix = [[1, 2], [3, 4], [5, 6]]
flattened = [item for sublist in matrix for item in sublist]
print(flattened) # [1, 2, 3, 4, 5, 6]
# Using itertools.chain
from itertools import chain
combined = list(chain([1, 2], [3, 4], [5, 6]))
print(combined) # [1, 2, 3, 4, 5, 6]
🔄 Looping Through Lists (All Methods)
| Method | Syntax | Use Case |
|---|---|---|
| Basic for loop | for item in list: |
Access each item directly |
| With index (range) | for i in range(len(list)): |
Need index to modify list |
| enumerate() | for i, item in enumerate(list): |
Need both index and item |
| While loop | while i < len(list): |
Complex conditions |
| List comprehension | [expr for item in list] |
Creating new lists |
| zip() for parallel | for a, b in zip(list1, list2): |
Loop multiple lists together |
fruits = ["apple", "banana", "cherry"]
# Method 1: Basic for loop (access items)
print("Method 1 - Basic for loop:")
for fruit in fruits:
print(fruit)
# Method 2: Loop with index (using range)
print("\nMethod 2 - With index:")
for i in range(len(fruits)):
print(f"Index {i}: {fruits[i]}")
# Method 3: Using enumerate (best for index + value)
print("\nMethod 3 - Using enumerate:")
for i, fruit in enumerate(fruits):
print(f"Index {i}: {fruit}")
# Method 4: While loop
print("\nMethod 4 - While loop:")
i = 0
while i < len(fruits):
print(fruits[i])
i += 1
# Method 5: List comprehension
print("\nMethod 5 - List comprehension:")
upper_fruits = [fruit.upper() for fruit in fruits]
print(upper_fruits)
# Method 6: Looping backwards
print("\nLooping backwards:")
for fruit in reversed(fruits):
print(fruit)
# Method 7: Looping with condition
print("\nFruits with length > 5:")
for fruit in fruits:
if len(fruit) > 5:
print(fruit)
# Method 8: Using zip() for multiple lists
names = ["Amit", "Neha", "Raj"]
ages = [25, 24, 26]
print("\nParallel looping with zip:")
for name, age in zip(names, ages):
print(f"{name} is {age} years old")
# Method 9: Modifying list while looping
print("\nModifying list (square numbers):")
numbers = [1, 2, 3, 4, 5]
for i in range(len(numbers)):
numbers[i] = numbers[i] ** 2
print(numbers) # [1, 4, 9, 16, 25]
# Method 10: Nested loops for 2D lists
matrix = [[1, 2], [3, 4], [5, 6]]
print("\nNested loops for matrix:")
for row in matrix:
for item in row:
print(item, end=" ")
print()
🔢 Counting in Lists
numbers = [1, 2, 3, 2, 4, 2, 5]
print(f"Count of 2: {numbers.count(2)}") # 3
print(f"Length: {len(numbers)}") # 7
print(f"Sum: {sum(numbers)}") # 19
print(f"Maximum: {max(numbers)}") # 5
print(f"Minimum: {min(numbers)}") # 1
# Count even numbers
even_count = sum(1 for n in numbers if n % 2 == 0)
print(f"Even numbers: {even_count}") # 4 (2,2,4,2)
# Count strings by length
words = ["cat", "elephant", "dog", "butterfly"]
long_words = sum(1 for w in words if len(w) > 5)
print(f"Words longer than 5 chars: {long_words}") # 2
# Frequency of all items
from collections import Counter
freq = Counter(numbers)
print(f"Frequency: {freq}") # Counter({2: 3, 1: 1, 3: 1, 4: 1, 5: 1})
📚 Complete List Methods Summary
Adding Methods
append(item)- Add to endinsert(i, item)- Insert at indexextend(iterable)- Add multiple
Removing Methods
remove(item)- Remove by valuepop(i)- Remove by indexclear()- Remove all
Ordering Methods
sort()- Sort in-placereverse()- Reverse in-place
Information Methods
index(item)- Find positioncount(item)- Count occurrencescopy()- Shallow copy
What it is: An ordered, unchangeable (immutable) collection. Can hold mixed types.
Real-life: Days of week ("Mon", "Tue"), fixed coordinates (28.6, 77.2), RGB colors (255,255,0), months of year.
📦 Creating Tuples
| Syntax | Description | Example | Result |
|---|---|---|---|
() | Empty tuple | empty = () | () |
(item,) | Single item (comma required!) | single = (5,) | (5,) |
item1, item2 | Without parentheses | colors = "red", "green" | ("red","green") |
tuple() | From other sequence | tuple([1,2,3]) | (1,2,3) |
🔍 Tuple Operations (Immutable)
| Operation | Description | Example | Result |
|---|---|---|---|
[] | Indexing | t = (10,20,30); t[1] | 20 |
[:] | Slicing | t[1:3] | (20,30) |
+ | Concatenation | (1,2) + (3,4) | (1,2,3,4) |
* | Repetition | (1,2) * 3 | (1,2,1,2,1,2) |
in | Membership | 2 in (1,2,3) | True |
📋 Tuple Methods
| Method | Description | Example | Result |
|---|---|---|---|
.count() | Count occurrences | (1,2,2,3).count(2) | 2 |
.index() | Find first index | (1,2,3).index(2) | 1 |
🎁 Packing and Unpacking
# Packing
point = 10, 20, 30 # (10, 20, 30)
# Unpacking
x, y, z = point # x=10, y=20, z=30
# Swapping variables (uses tuple packing/unpacking)
a, b = 5, 10
a, b = b, a # a=10, b=5
# Extended unpacking (Python 3)
first, *rest = (1, 2, 3, 4) # first=1, rest=[2,3,4]
*begin, last = (1, 2, 3, 4) # begin=[1,2,3], last=4
🔢 Counting in Tuples
t = (1, 2, 3, 2, 4, 2, 5)
print(len(t)) # 7
print(t.count(2)) # 3
print(sum(t)) # 19
print(max(t)) # 5
print(min(t)) # 1
# Count even numbers
even_count = sum(1 for n in t if n % 2 == 0)
print(even_count) # 4 (2,2,4,2)
# Convert to list if you need to modify
l = list(t) # [1,2,3,2,4,2,5]
💡 When to Use Tuples
- Fixed data: Days of week, months, coordinates that shouldn't change
- Dictionary keys: Tuples can be keys (lists cannot because they're mutable)
- Function arguments:
*argsis a tuple - Return multiple values: Functions return tuples by default
- Performance: Tuples are slightly faster than lists
- Data integrity: Prevents accidental modification
What it is: Unordered, changeable collection of key-value pairs. Keys must be unique and immutable (strings, numbers, tuples).
Real-life: Phonebook (name→number), student record, dictionary (word→definition), JSON data, configuration settings.
📖 Creating Dictionaries
| Method | Example | Result |
|---|---|---|
| Curly braces | {"name":"Amit", "age":25} | {'name':'Amit','age':25} |
dict() constructor | dict(name="Amit", age=25) | {'name':'Amit','age':25} |
| From list of tuples | dict([("name","Amit"), ("age",25)]) | {'name':'Amit','age':25} |
Using zip() | dict(zip(["name","age"], ["Amit",25])) | {'name':'Amit','age':25} |
🔑 Dictionary Methods
| Method | Description | Example |
|---|---|---|
.keys() | Get all keys | student.keys() → dict_keys(['name','age']) |
.values() | Get all values | student.values() → dict_values(['Amit',25]) |
.items() | Get key-value pairs | student.items() → dict_items([('name','Amit'),('age',25)]) |
.get(key, default) | Safe access (no error if missing) | student.get("phone", "Not found") |
.setdefault(key, default) | Get value or set default if missing | student.setdefault("grade", "A") |
.update(dict2) | Merge dictionaries | student.update({"city":"Patna"}) |
.pop(key) | Remove key and return value | age = student.pop("age") |
.popitem() | Remove and return last inserted (Python 3.7+) | student.popitem() |
.clear() | Remove all items | student.clear() |
.copy() | Shallow copy | new = student.copy() |
in operator | Check if key exists | "name" in student → True |
📝 Adding and Updating
student = {"name": "Amit", "age": 25}
# Add/update single key
student["city"] = "Patna" # Add new
student["age"] = 26 # Update
# Add multiple keys
student.update({"grade": "A", "roll": 101})
# Safe add (only if key doesn't exist)
student.setdefault("phone", "N/A") # Adds phone: "N/A" if not present
❌ Removing Items
# Remove specific key
del student["city"] # Remove key
age = student.pop("age") # Remove and return value
# Remove last inserted (Python 3.7+)
last = student.popitem() # Returns ('roll', 101)
# Clear all
student.clear() # {}
🔄 Looping Through Dictionaries
person = {"name": "Amit", "age": 25, "city": "Patna"}
# Loop through keys
for key in person:
print(key, person[key])
# Loop through keys (explicit)
for key in person.keys():
print(key)
# Loop through values
for value in person.values():
print(value)
# Loop through key-value pairs
for key, value in person.items():
print(f"{key}: {value}")
🔢 Counting with Dictionaries
# Frequency counter (most common use case)
words = ["apple", "banana", "apple", "orange", "banana", "apple"]
freq = {}
for word in words:
freq[word] = freq.get(word, 0) + 1
print(freq) # {'apple': 3, 'banana': 2, 'orange': 1}
# Using collections.Counter
from collections import Counter
counter = Counter(words)
print(counter) # Counter({'apple': 3, 'banana': 2, 'orange': 1})
print(counter.most_common(1)) # [('apple', 3)]
# Dictionary length
print(len(person)) # 3 (number of key-value pairs)
# Count specific values
grades = {"Amit": "A", "Neha": "B", "Raj": "A", "Priya": "C"}
a_count = list(grades.values()).count("A")
print(a_count) # 2
# Group items by category
students = [("Amit", "A"), ("Neha", "B"), ("Raj", "A"), ("Priya", "C")]
by_grade = {}
for name, grade in students:
by_grade.setdefault(grade, []).append(name)
print(by_grade) # {'A': ['Amit', 'Raj'], 'B': ['Neha'], 'C': ['Priya']}
🧩 Nested Dictionaries
# Dictionary containing dictionaries
school = {
"class1": {
"teacher": "Mr. Sharma",
"students": ["Amit", "Neha", "Raj"]
},
"class2": {
"teacher": "Ms. Gupta",
"students": ["Priya", "Rahul"]
}
}
print(school["class1"]["teacher"]) # Mr. Sharma
print(school["class2"]["students"][0]) # Priya
# Dictionary containing lists
student = {
"name": "Amit",
"scores": [85, 90, 78],
"subjects": ["Math", "Physics", "Chemistry"]
}
average = sum(student["scores"]) / len(student["scores"])
print(f"{student['name']}'s average: {average:.2f}")
💡 Dictionary Comprehensions
# Square numbers
squares = {x: x**2 for x in range(5)} # {0:0, 1:1, 2:4, 3:9, 4:16}
# Filter items
even_squares = {x: x**2 for x in range(10) if x % 2 == 0}
# Swap keys and values
original = {"a": 1, "b": 2, "c": 3}
swapped = {value: key for key, value in original.items()} # {1:'a', 2:'b', 3:'c'}
🔍 How to Check Type
x = 10
print(type(x)) #
y = "Hello"
print(type(y)) #
z = [1, 2, 3]
print(type(z)) #
w = {"a": 1, "b": 2}
print(type(w)) #
Use type() function to see what type Python assigned
📌 Quick Summary
int → Whole numbers: 10, 25, -5
float → Decimals: 3.14, 99.9
str → Text: "Hello", 'Python'
bool → True/False
list → [1, 2, 3] (changeable)
tuple → (1, 2, 3) (fixed)
dict → {"key": "value"}
💡 Python auto-detects types!
3.4 Mutable vs Immutable (Very Simple Explanation)
"Mutable" means can be changed, "Immutable" means cannot be changed.
📌 Comparison Table
| Type | Examples | Change Allowed? |
|---|---|---|
| Mutable | list, dict, set | ✔ Yes |
| Immutable | int, float, str, tuple | ❌ No |
myList[0] = 10
String cannot → "hello" cannot be modified.
3.5 How to Check Data Types using type()
Python's built-in type() function tells you what kind of data a variable contains —
like a label on a container!
Code
age = 25
price = 99.99
name = "Rahul"
is_student = True
fruits = ["apple", "banana"]
print(type(age))
print(type(price))
print(type(name))
print(type(is_student))
print(type(fruits))
Output
<class 'int'>
<class 'float'>
<class 'str'>
<class 'bool'>
<class 'list'>
Check Without Variable:
print(type(10)) # <class 'int'>print(type("Hi")) # <class 'str'>
🎯 Key Point
Variables store data, data types define what kind of value,
and type() helps you confirm it. Use it anytime you're unsure!
🎓 Module 03 : Python Variables & Data Types Successfully Completed
You have successfully completed this module of Python for Cybersecurity.
Keep building your expertise step by step — Learn Next Module →
Python Operators – Easy Explanations with Examples
This module explains all Python operators with simple explanations, real-life examples, and clear tables to make learning easy.
4.1 Arithmetic Operators (Daily-Life Examples)
Arithmetic operators help us perform mathematical operations like addition, subtraction, etc. Think of them as the math symbols you use every day!
| Operator | Meaning | Example | Output | Real-Life Use |
|---|---|---|---|---|
| + | Addition | 10 + 5 |
15 | Total bill: ₹150 + ₹50 = ₹200 |
| - | Subtraction | 20 - 3 |
17 | Change: ₹500 - ₹325 = ₹175 |
| * | Multiplication | 4 * 5 |
20 | Cost of 3 pizzas: ₹150 × 3 = ₹450 |
| / | Division | 20 / 4 |
5.0 | Split bill: ₹1000 ÷ 4 people = ₹250 each |
| % | Modulus (Remainder) | 10 % 3 |
1 | Remaining chocolates after distributing 10 among 3 kids → 1 left |
| ** | Exponent (Power) | 2 ** 3 |
8 | Square feet: 10² = 100 sq.ft |
| // | Floor Division | 10 // 3 |
3 | How many full boxes? 10 items, 3 per box → 3 boxes (ignore remainder) |
🛒 More Daily Life Examples in Python
# Monthly salary with bonus
basic_salary = 25000
bonus = 2000
tax = 2500
total_salary = basic_salary + bonus - tax
print(f"Salary after bonus and tax: ₹{total_salary}")
# Output: Salary after bonus and tax: ₹24500
Addition: basic + bonus
Subtraction: subtract tax
# Calculate mileage
distance_km = 350
fuel_liters = 12.5
mileage = distance_km / fuel_liters
print(f"Car mileage: {mileage:.1f} km/liter")
# Output: Car mileage: 28.0 km/liter
Division: distance ÷ fuel
# Simple EMI calculation
loan_amount = 500000
months = 60
interest_rate = 0.08 # 8% annual
monthly_interest = loan_amount * interest_rate / 12
total_payment = loan_amount + (monthly_interest * months)
print(f"Monthly interest: ₹{monthly_interest:.0f}")
print(f"Total payment: ₹{total_payment:.0f}")
# Output: Monthly interest: ₹3333
# Output: Total payment: ₹700000
# Scale recipe for more people
original_servings = 4
new_servings = 6
rice_needed = 2 # cups for 4 people
scale_factor = new_servings / original_servings
rice_now = rice_needed * scale_factor
print(f"Scale factor: {scale_factor}")
print(f"Rice needed: {rice_now} cups")
# Output: Scale factor: 1.5
# Output: Rice needed: 3.0 cups
# Convert minutes to hours and minutes
total_minutes = 145
hours = total_minutes // 60
minutes = total_minutes % 60
print(f"{total_minutes} minutes = {hours} hours {minutes} minutes")
# Output: 145 minutes = 2 hours 25 minutes
// gets hours, % gets remaining minutes
# Calculate required run rate
target = 250
overs = 50
scored = 120
overs_played = 30
runs_needed = target - scored
overs_left = overs - overs_played
required_rate = runs_needed / overs_left
print(f"Runs needed: {runs_needed}")
print(f"Required rate: {required_rate:.2f} runs/over")
# Output: Runs needed: 130, Required rate: 6.50 runs/over
# Calculate final price after discount
original_price = 1999
discount_percent = 20 # 20% off
discount_amount = original_price * discount_percent / 100
final_price = original_price - discount_amount
print(f"Original: ₹{original_price}")
print(f"Discount: ₹{discount_amount}")
print(f"Pay only: ₹{final_price}")
# Output: Original: ₹1999, Discount: ₹399.8, Pay only: ₹1599.2
# Celsius to Fahrenheit
celsius = 37
fahrenheit = (celsius * 9/5) + 32
print(f"{celsius}°C = {fahrenheit}°F")
# Check if fever (above 98.6°F)
if fahrenheit > 98.6:
print("You have fever!")
# Output: 37°C = 98.6°F
# Calculate electricity bill
units = 250
rate_per_unit = 6.5
fixed_charge = 100
bill_amount = units * rate_per_unit + fixed_charge
print(f"Units consumed: {units}")
print(f"Total bill: ₹{bill_amount}")
# Output: Units consumed: 250, Total bill: ₹1725.0
# Calculate age in months and days
years = 25
months_in_year = 12
days_in_year = 365
age_in_months = years * months_in_year
age_in_days = years * days_in_year
print(f"Age: {years} years")
print(f"That's {age_in_months} months")
print(f"Or about {age_in_days} days")
# Output: Age: 25 years, That's 300 months, Or about 9125 days
🎯 Operator Usage Summary
⚠️ Note on Division:
/ always returns float (decimal) result.
10 / 2 = 5.0 (not 5)
⚠️ Note on Floor Division:
// rounds down to nearest integer.
10 // 3 = 3, -10 // 3 = -4
✏️ Try These Yourself
📌 Quick Summary
+ - * Basic math
/ Division (float)
% Remainder
** Power
// Floor division
4.2 Assignment Operators Explained Simply
Assignment operators help you store values in variables or update existing ones. Think of them as shortcuts that combine math and assignment in one step!
x = 10, you're telling Python:
"Put the value 10 into the box named x". That's assignment!
📊 Complete Assignment Operators
| Operator | Meaning | Example | Long Form | Result (if x starts as 10) |
|---|---|---|---|---|
| = | Assign value | x = 10 |
x = 10 |
x = 10 |
| += | Add & assign | x += 5 |
x = x + 5 |
x = 15 |
| -= | Subtract & assign | x -= 3 |
x = x - 3 |
x = 7 |
| *= | Multiply & assign | x *= 2 |
x = x * 2 |
x = 20 |
| /= | Divide & assign | x /= 2 |
x = x / 2 |
x = 5.0 |
| %= | Modulus & assign | x %= 3 |
x = x % 3 |
x = 1 |
| **= | Exponent & assign | x **= 2 |
x = x ** 2 |
x = 100 |
| //= | Floor division & assign | x //= 3 |
x = x // 3 |
x = 3 |
🛒 Daily Life Examples
# Start with empty cart
total = 0
# Add items one by one
total += 350 # Add shirt
total += 200 # Add jeans
total += 150 # Add shoes
print(f"Total bill: ₹{total}")
# Output: Total bill: ₹700
# Apply discount
total -= 70 # 10% discount
print(f"After discount: ₹{total}")
# Output: After discount: ₹630
+= adds items to cart
-= applies discount
# Player starts at 0
score = 0
# Player collects coins
score += 100 # Found gold coin
score += 50 # Found silver coin
score *= 2 # Bonus multiplier!
print(f"Final score: {score}")
# Player loses a life
lives = 3
lives -= 1 # Lost one life
print(f"Lives left: {lives}")
# Output: Final score: 300
# Output: Lives left: 2
# Initial balance
balance = 5000
# Transactions
balance += 2000 # Salary credited
balance -= 500 # ATM withdrawal
balance *= 1.05 # 5% interest
print(f"Current balance: ₹{balance:.2f}")
# Output: Current balance: ₹6825.00
# Initial investment
shares = 100
price_per_share = 50
investment = shares * price_per_share
# Stock split (2-for-1)
shares *= 2
price_per_share /= 2
print(f"Shares now: {shares}")
print(f"Price now: ₹{price_per_share}")
# Output: Shares now: 200, Price now: ₹25.0
🔄 Counters and Loops (Very Common!)
# Count from 1 to 5
count = 0
count += 1 # count = 1
count += 1 # count = 2
count += 1 # count = 3
count += 1 # count = 4
count += 1 # count = 5
# In loops (very common!)
for i in range(5):
count += 1 # Shortcut for count = count + 1
count += 1 is used in 90% of loops!
# Countdown from 5
countdown = 5
countdown -= 1 # 4
countdown -= 1 # 3
countdown -= 1 # 2
countdown -= 1 # 1
countdown -= 1 # 0
print("Blast off!")
# In while loops
while countdown > 0:
countdown -= 1
print(f"{countdown}...")
⚠️ Important Things to Remember
1. Variable Must Exist First
You can't use += on a variable that doesn't exist!
# This will ERROR:
# score += 10 # score doesn't exist!
# Do this first:
score = 0
score += 10 # Now it works!
2. Division Changes Type
/= always gives float result
x = 10
x /= 2 # x becomes 5.0 (float)
print(x) # 5.0
# Use //= for integer result
y = 10
y //= 3 # y becomes 3 (int)
Try These Yourself
Problem 1:
Start with x = 5. Do x += 3, then x *= 2. What's x?
Problem 2:
Start with money = 100. Add 50, then subtract 30. What's left?
Problem 3:
Start with n = 8. Do n **= 2, then n //= 4. What's n?
📋 Where Are They Used?
📌 Quick Summary
✅ = assigns initial value
✅ += -= *= /= update values (math + assignment)
✅ Always initialize variables before using += etc.
✅ count += 1 is extremely common in loops
✅ They make code shorter and more readable
total += item_price is much cleaner than
total = total + item_price. Get used to them!
4.3 Comparison Operators (==, >, <, !=)
These operators compare two values and return True or False. They're like questions you ask Python – and it answers with Yes (True) or No (False)!
📊 Complete Comparison Operators
| Operator | Meaning | Example | Question in English | Output |
|---|---|---|---|---|
| == | Equal to | 5 == 5 |
"Is 5 equal to 5?" | True |
| != | Not equal to | 5 != 3 |
"Is 5 not equal to 3?" | True |
| > | Greater than | 7 > 2 |
"Is 7 greater than 2?" | True |
| < | Less than | 3 < 2 |
"Is 3 less than 2?" | False |
| >= | Greater than or equal to | 5 >= 5 |
"Is 5 greater than or equal to 5?" | True |
| <= | Less than or equal to | 4 <= 6 |
"Is 4 less than or equal to 6?" | True |
⚠️ VERY IMPORTANT: == vs =
This is the most common mistake beginners make!
= is for assignment
x = 10 # Put 10 into x
== is for comparison
x == 10 # Ask: Is x equal to 10?
🏠 Daily Life Examples
age = 18
# Can you vote?
can_vote = age >= 18
print(f"Can vote: {can_vote}")
# Can you drive?
can_drive = age >= 16
print(f"Can drive: {can_drive}")
# Are you a senior citizen?
is_senior = age >= 60
print(f"Is senior: {is_senior}")
# Output: Can vote: True
# Output: Can drive: True
# Output: Is senior: False
temperature = 39.5 # Celsius
# Check for fever
has_fever = temperature > 37.5
print(f"Has fever: {has_fever}")
# Check if too cold
is_cold = temperature < 20
print(f"Is cold: {is_cold}")
# Perfect temperature?
is_perfect = temperature == 37
print(f"Perfect: {is_perfect}")
# Output: Has fever: True
# Output: Is cold: False
# Output: Perfect: False
marks = 85
passing_marks = 40
distinction_marks = 75
# Check if passed
passed = marks >= passing_marks
print(f"Passed: {passed}")
# Check if failed
failed = marks < passing_marks
print(f"Failed: {failed}")
# Check if distinction
got_distinction = marks >= distinction_marks
print(f"Distinction: {got_distinction}")
# Check exact score
perfect_score = marks == 100
print(f"Perfect score: {perfect_score}")
# Output: Passed: True, Failed: False
# Output: Distinction: True, Perfect score: False
battery = 15
# Low battery warning
low_battery = battery <= 20
print(f"Low battery: {low_battery}")
# Full battery?
full_battery = battery == 100
print(f"Full: {full_battery}")
# Critical battery
critical = battery <= 5
print(f"Critical: {critical}")
if low_battery:
print("⚠️ Please charge your phone!")
# Output: Low battery: True
# Output: Full: False
# Output: Critical: False
# Output: ⚠️ Please charge your phone!
📝 Comparing Text (Strings)
# Names comparison
name1 = "Rahul"
name2 = "Rahul"
name3 = "Amit"
print(name1 == name2) # True (same name)
print(name1 == name3) # False (different)
print(name1 != name3) # True (not equal)
# Password check
password = "secret123"
user_input = "secret123"
if user_input == password:
print("Access granted!")
else:
print("Wrong password!")
# Output: Access granted!
⚠️ Important: Case Sensitivity
# Python is case-sensitive!
"Rahul" == "rahul" # False (R != r)
"PYTHON" == "python" # False
"Hello" == "Hello" # True
# Fix by converting to same case
name = "Rahul"
input_name = "RAHUL"
# Convert both to lowercase
print(name.lower() == input_name.lower()) # True!
🔗 Combining Comparisons
# Check if number is between 10 and 20
x = 15
is_between = x > 10 and x < 20
print(f"Between 10 and 20: {is_between}")
# Check if outside range
is_outside = x < 10 or x > 20
print(f"Outside range: {is_outside}")
# Python shortcut (works in Python!)
is_between = 10 < x < 20
print(f"Using shortcut: {is_between}")
# Output: Between: True, Outside: False, Shortcut: True
# Eligibility checker
age = 25
has_license = True
can_drive = age >= 18 and has_license
print(f"Can drive: {can_drive}")
# Weekend check
day = "Sunday"
is_weekend = day == "Saturday" or day == "Sunday"
print(f"Is weekend: {is_weekend}")
# Output: Can drive: True
# Output: Is weekend: True
🚀 Where They're Used
🔐 Login Systems
if user_input == password:
🎮 Games
if score > high_score:
🛒 Shopping
if total >= 500: # free shipping
📊 Filters
if price <= budget:
✅ Validation
if age >= 18:
🔍 Search
if item == search_term:
✏️ Try These Yourself
1. 10 > 5 ?
2. 7 == 8 ?
3. 15 <= 15 ?
4. "Ram" == "Ram" ?
⚠️ Common Mistakes to Avoid
- Using = instead of == - Remember: = is assignment, == is comparison
- Forgetting case sensitivity - "Hello" != "hello"
- Comparing different types - "5" == 5 is False (string vs number)
- Using = in conditions - if x = 10: will cause error!
📌 Quick Reference
🎯 Key Takeaways
✅ Comparison operators ask questions and return True/False
✅ Use == to check equality (not =)
✅ Used everywhere in if statements, loops, and conditions
✅ Strings are compared exactly (case matters!)
✅ You can combine them with and/or for complex conditions
4.4 Logical Operators (and, or, not)
Logical operators are used to combine multiple conditions. Think of them as decision makers that help you check multiple rules at once!
• and = ALL conditions must be True
• or = AT LEAST ONE condition must be True
• not = REVERSE the condition
📊 Truth Table (How They Work)
| A | B | Answer |
|---|---|---|
| True | True | True |
| True | False | False |
| False | True | False |
| False | False | False |
| A | B | Answer |
|---|---|---|
| True | True | True |
| True | False | True |
| False | True | True |
| False | False | False |
| A | Answer |
|---|---|
| True | False |
| False | True |
🏠 Daily Life Examples
# Student details
marks = 85
attendance = 90
has_recommendation = True
# AND: All conditions must be True
admission = marks >= 80 and attendance >= 75 and has_recommendation
print(f"Admission granted: {admission}")
# More readable version
if marks >= 80 and attendance >= 75 and has_recommendation:
print("✅ You're admitted!")
else:
print("❌ Not eligible")
# Output: ✅ You're admitted!
# Family movie decision
is_comedy = True
is_action = False
is_animation = False
# OR: At least one must be True
can_watch = is_comedy or is_action or is_animation
print(f"Can watch: {can_watch}")
if is_comedy or is_action or is_animation:
print("🍿 Let's watch the movie!")
else:
print("❌ No one likes this genre")
# Output: Can watch: True, 🍿 Let's watch the movie!
# Check if withdrawal is possible
balance = 5000
pin_correct = True
daily_limit = 10000
withdrawal_amount = 3000
# AND: All conditions must be met
can_withdraw = (pin_correct and
withdrawal_amount <= balance and
withdrawal_amount <= daily_limit)
print(f"Can withdraw: {can_withdraw}")
if can_withdraw:
print("💰 Please take your cash")
else:
print("❌ Transaction failed")
# Output: Can withdraw: True, 💰 Please take your cash
# Is the user not logged in?
is_logged_in = False
if not is_logged_in:
print("🔐 Please login first")
# Is the item not in stock?
in_stock = False
if not in_stock:
print("📦 Out of stock")
# Is the password not correct?
password_correct = False
if not password_correct:
print("❌ Wrong password")
# Output: 🔐 Please login first
# Output: 📦 Out of stock
# Output: ❌ Wrong password
🧩 Combining Multiple Operators
# Job eligibility
age = 25
experience = 3
degree = "B.Tech"
has_certification = True
# Complex condition
eligible = (age >= 21 and age <= 60) and \
(experience >= 2 or has_certification) and \
(degree == "B.Tech" or degree == "MCA")
print(f"Eligible for job: {eligible}")
# With NOT: Are they overqualified?
overqualified = not (age <= 40 and experience <= 5)
print(f"Overqualified: {overqualified}")
# Output: Eligible for job: True
# Output: Overqualified: False
# Choosing a restaurant
budget = 500
veg_options = True
waiting_time = 15 # minutes
rating = 4.2
# Can we go?
can_go = (budget <= 800) and \
(veg_options or waiting_time < 20) and \
(rating >= 4.0)
print(f"Can go to restaurant: {can_go}")
# Not too expensive?
not_expensive = not (budget > 1000)
print(f"Not expensive: {not_expensive}")
# Output: Can go to restaurant: True
# Output: Not expensive: True
⚡ Short-Circuit Evaluation (Important!)
Python stops checking as soon as it knows the answer!
AND short-circuits:
# Python stops at first False
x = 5
if x > 10 and x / 0 == 1:
print("This won't run")
# No error! Python stops at x > 10 (False)
OR short-circuits:
# Python stops at first True
y = 5
if y < 10 or y / 0 == 1:
print("This runs safely")
# No error! Python stops at y < 10 (True)
🚀 Real-World Applications
🔐 Login
if user and pass:
🛒 Shopping
if in_stock and price <= budget:
🎮 Games
if health > 0 and not game_over:
📊 Filters
if price < 1000 or rating > 4:
✏️ Try These Yourself
1. True and False = ?
2. True or False = ?
3. not (5 > 3) = ?
4. (5 > 3) and (2 < 4) = ?
⚠️ Common Mistakes
- Using and/or incorrectly: In English we say "x is between 1 and 5" but in Python:
x > 1 and x < 5 - Forgetting parentheses:
age > 18 and score > 60 or has_pass- use parentheses to make it clear:(age > 18 and score > 60) or has_pass - Using & instead of and: & is for bitwise operations, use 'and' for logical conditions
- not vs != :
not (x == y)is same asx != y
📌 Quick Reference
🎯 Key Takeaways
✅ and = ALL conditions must be True
✅ or = ANY condition can be True
✅ not = FLIPS the result
✅ Python uses short-circuit evaluation (stops early)
✅ Use parentheses to make complex conditions clear
4.5 Bitwise & Ternary Operators (Simple Explanation)
🔹 Ternary Operator (The One-Line If-Else)
The ternary operator is a shortcut for writing if-else statements in just one line. It's like asking a question and getting an answer immediately!
value_if_true if condition else value_if_false
age = 20
# Normal if-else (3 lines)
if age >= 18:
status = "Adult"
else:
status = "Minor"
# Ternary operator (1 line)
status = "Adult" if age >= 18 else "Minor"
print(status) # Adult
marks = 85
passing = 40
# Ternary makes it compact
result = "Pass" if marks >= passing else "Fail"
print(result) # Pass
# Even with multiple conditions
grade = "A" if marks >= 75 else "B" if marks >= 60 else "C"
print(grade) # A
💰 Discount
price = 100 if member else 150
🌙 Time of Day
greeting = "Good Morning" if hour < 12 else "Good Afternoon"
📱 Battery
alert = "Low" if battery < 20 else "OK"
🔹 Bitwise Operators (Working with Bits)
Computers store everything as bits (0s and 1s). Bitwise operators let you manipulate these bits directly. It's like working with light switches!
| Operator | Name | Example | Binary Explanation | Result |
|---|---|---|---|---|
| & | Bitwise AND | 5 & 3 |
0101 & 0011 = 0001 | 1 |
| | | Bitwise OR | 5 | 3 |
0101 | 0011 = 0111 | 7 |
| ^ | Bitwise XOR | 5 ^ 3 |
0101 ^ 0011 = 0110 | 6 |
| ~ | Bitwise NOT | ~5 |
~0101 = ...1010 (2's complement) | -6 |
| << | Left Shift | 5 << 1 |
0101 << 1 = 1010 | 10 |
| >> | Right Shift | 5 >> 1 |
0101 >> 1 = 0010 | 2 |
🎯 Visual Example: 5 & 3 (AND)
| Bit position | 8 | 4 | 2 | 1 |
|---|---|---|---|---|
| 5 in binary | 0 | 1 | 0 | 1 |
| 3 in binary | 0 | 0 | 1 | 1 |
| Result (AND) | 0 | 0 | 0 | 1 |
AND: Both bits must be 1 to get 1
Where Bitwise Operators Are Used:
⚖️ When to Use Each
- You have simple if-else conditions
- You want to assign a value based on a condition
- You need to make code more compact
- Example:
min = a if a < b else b
- Working with hardware/embedded systems
- Performance-critical code
- Manipulating individual bits (flags, permissions)
- Advanced: cryptography, compression
⚠️ Common Mistakes
- Confusing & with and:
if x & y(bitwise) vsif x and y(logical) - Ternary overuse: Don't nest ternary operators - it becomes unreadable!
- Forgetting operator precedence: Use parentheses to be safe:
(x & y) == z
✏️ Quick Practice
Ternary: Write "Even" if x is even, else "Odd"
Bitwise: 6 & 3 = ?
Bitwise: 4 << 2 = ?
📌 Quick Reference
🎉 Chapter Summary
✅ Ternary operator = compact if-else: x if condition else y
✅ Bitwise operators work on bits - great for low-level programming
✅ As a beginner, focus on ternary; bitwise can come later
✅ Python has many operators to perform math, compare values, make decisions, and manipulate data!
4.6 Membership Operators (in, not in)
🔹 Membership Operators (The "Is It There?" Operators)
Membership operators check if a value exists inside a sequence (like strings, lists, tuples, or dictionaries). It's like asking Python: "Is this item present?" and getting a Yes (True) or No (False) answer!
value in sequence → Returns True if value existsvalue not in sequence → Returns True if value does NOT exist
# Shopping list
shopping_list = ["milk", "bread", "eggs", "rice"]
# Check if milk is in the list
item = "milk"
if item in shopping_list:
print(f"✅ {item} is already in the list!")
else:
print(f"❌ {item} not in list, add it!")
# Check if coffee is NOT in the list
if "coffee" not in shopping_list:
print("☕ Add coffee to the list!")
# Output: ✅ milk is already in the list!
# Output: ☕ Add coffee to the list!
# Check if email has @ symbol
email = "rahul@gmail.com"
if "@" in email and "." in email:
print("✅ Valid email format")
else:
print("❌ Invalid email")
# Check for spam keywords
message = "You won a lottery!"
spam_words = ["won", "lottery", "prize", "winner"]
is_spam = any(word in message.lower() for word in spam_words)
if is_spam:
print("⚠️ This might be spam!")
# Output: ✅ Valid email format
# Output: ⚠️ This might be spam!
🔤 String Check
"Py" in "Python" → True"java" in "Python" → False
📋 List Check
5 in [1,3,5,7] → True2 in [1,3,5,7] → False
🔑 Dictionary Check
"name" in {"name":"Raj"} → True"Raj" in {"name":"Raj"} → False (checks keys only!)
🔹 Working with Different Data Types
in checks the keys, not values!
student = {"name": "Rahul", "age": 25, "city": "Delhi"}
"name" in student # True (checks if "name" is a key)
"Rahul" in student # False (Rahul is a value, not a key)
25 in student # False (age is a key, but 25 is a value)
| Data Type | Example | Result | Explanation |
|---|---|---|---|
| String | "a" in "apple" |
True | 'a' appears in "apple" |
| String | "z" in "apple" |
False | 'z' does NOT appear |
| List | 3 in [1,2,3,4] |
True | 3 is in the list |
| List | 5 in [1,2,3,4] |
False | 5 is NOT in the list |
| Tuple | "mon" in ("mon","tue") |
True | "mon" is in the tuple |
| Dictionary | "name" in {"name":"Raj"} |
True | Checks KEYS, not values |
| not in | "x" not in "hello" |
True | 'x' is NOT in "hello" |
🎯 Visual Example: "a" in "banana"
b a n a n a
position: 0 1 2 3 4 5
Position 3: a ✓
RESULT: True (found!)
in operator: Scans through the sequence until it finds a match!
Where Membership Operators Are Used:
⚖️ When to Use Each
- You need to check if an item exists in a collection
- You're searching for a substring in a string
- You want to validate if a key exists in a dictionary
- Example:
if user_input in valid_options: - Example:
if "@" in email:
- You need to check if an item is NOT present
- You're filtering out unwanted values
- You want to check for missing items
- Example:
if item not in blacklist: - Example:
if "error" not in log_message:
⚠️ Common Mistakes
- Forgetting that dictionaries check keys only:
"value" in {"key":"value"}is False! - Case sensitivity:
"A" in "apple"is False (uppercase vs lowercase) - Using in with incompatible types:
5 in "hello"works but checks for substring "5"? - Confusing membership with equality:
"a" in ["a"]is True, but"a" == ["a"]is False
✏️ Quick Practice
1. "a" in "cat" → ?
2. 5 in [1,3,5,7] → ?
3. "x" not in "hello" → ?
4. "age" in {"name":"Raj", "age":25} → ?
5. "Raj" in {"name":"Raj", "age":25} → ?
6. 3 in (1,2,3,4) → ?
📌 Quick Reference
🎉 Chapter Summary
✅ in operator = checks if value exists in sequence → returns True/False
✅ not in operator = checks if value is missing → returns True/False
✅ Works with strings, lists, tuples, dictionaries (checks keys only!)
✅ Case-sensitive for strings: "A" and "a" are different
✅ Extremely useful for searching, validation, and filtering data!
4.7 Identity Operators (is, is not) Explained Simply
🔹 Identity Operators (The "Same Object?" Operators)
Identity operators check if two variables refer to the same object in memory. Think of it like asking: "Are these two things actually the same thing?" Not just equal values, but the exact same object!
x is y → True if x and y are the SAME objectx is not y → True if x and y are DIFFERENT objects
== checks VALUE (are they equal?)is checks IDENTITY (are they the same object?)
x = [1,2,3]
y = [1,2,3]
print(x == y) # True (same values)
print(x is y) # False (different lists!)
# Two variables pointing to SAME object
a = [1, 2, 3]
b = a # b refers to the SAME list as a
print(a is b) # True (same object)
print(a == b) # True (same values too)
# Modify through one variable
b.append(4)
print(a) # [1, 2, 3, 4] - a changed too!
print(b) # [1, 2, 3, 4]
# Output: True, True, [1,2,3,4], [1,2,3,4]
# Two variables with SAME values but DIFFERENT objects
x = [1, 2, 3]
y = [1, 2, 3] # New list with same values
print(x is y) # False (different objects)
print(x == y) # True (same values)
# Modify one doesn't affect the other
y.append(4)
print(x) # [1, 2, 3] - unchanged
print(y) # [1, 2, 3, 4] - changed
# Output: False, True, [1,2,3], [1,2,3,4]
🔢 Numbers
a = 10
b = 10
print(a is b) # True (Python caches small integers)
📝 Strings
s1 = "hello"
s2 = "hello"
print(s1 is s2) # True (string interning)
❌ None Check
x = None
if x is None:
print("x is None") # ALWAYS use 'is' for None!
🔹 Special Cases: When is Returns True Even for Different Variables
| Data Type | Example | Result | Explanation |
|---|---|---|---|
| Small Integers | a=5; b=5; a is b |
True | Python caches integers -5 to 256 |
| Large Integers | a=1000; b=1000; a is b |
False | Large integers are NOT cached |
| Short Strings | s1="hi"; s2="hi"; s1 is s2 |
True | String interning for small strings |
| Long Strings | s1="hello"*100; s2="hello"*100; s1 is s2 |
False | Long strings are NOT interned |
| Lists | l1=[1]; l2=[1]; l1 is l2 |
False | Lists are never reused |
| None | x=None; y=None; x is y |
True | None is a singleton (only one exists) |
| True/False | a=True; b=True; a is b |
True | Boolean values are singletons |
🎯 Visual Example: is vs ==
x
y
z = x
0x1234
0x5678
0x1234
[1,2,3]
[1,2,3]
[1,2,3]
x is x → True
x is y → False
x is z → True
Where Identity Operators Are Used:
⚖️ is vs ==: When to Use Each
- You want to check if values are the same
- Comparing numbers, strings, or collections
- Most normal comparison cases
- Example:
if user_input == "quit": - Example:
if score == high_score:
- Checking for None:
if x is None: - Checking boolean:
if x is True: - Testing if two variables point to same object
- Singleton pattern verification
- NEVER use 'is' for numbers/strings (unreliable!)
⚠️ Common Mistakes
- Using is instead of == for value comparison:
if x is 10:might work sometimes but DON'T do it! - Not understanding None checking: Always use
if x is None:, neverif x == None: - Assuming is works for all equal values:
1000 is 1000might be False! - Confusing identity with equality: Two lists with same values are NOT the same object
- Using is for string comparison:
"hello" is "hello"might be True due to interning, but don't rely on it!
✏️ Quick Practice
Identity: a=[1]; b=[1]; a is b → ?
Identity: a=[1]; b=a; a is b → ?
Identity: x = None; x is None → ?
Identity: 5 is 5 → ? (small integer)
Identity: 1000 is 1000 → ? (large integer)
Identity: "hi" is "hi" → ?
📌 Quick Reference
🎉 Chapter Summary
✅ is operator = checks if two variables point to the SAME object in memory
✅ is not operator = checks if they point to DIFFERENT objects
✅ ALWAYS use 'is' for None: if x is None: (this is the Python standard!)
✅ Don't use 'is' for numbers/strings - results can be unpredictable
✅ is checks identity (same object), == checks equality (same value)
✅ Lists, dicts, etc. with same values are NOT the same object (unless assigned)
🎓 Module 04 : Operators (Easy to Understand Examples) Successfully Completed
You have successfully completed this module of Python for Cybersecurity.
Keep building your expertise step by step — Learn Next Module →
🔍 Python Conditional Statements – If, Else & Elif (Easy & Practical)
Conditional statements allow Python to make decisions. With if, else, and elif, you can control the program flow based on conditions.
5.1 Understanding If Condition (Beginner-friendly)
🔹 If Condition (The Decision Maker)
The if condition helps your program make decisions. It's like asking a question: "If this is true, then do that." Think of it as a traffic light - if it's green, go!
if condition:
# code to execute if condition is True
# (indented with 4 spaces or tab)
⚠️ The indentation (spaces at the beginning) is VERY important in Python!
temperature = 35
# Normal way to think
if temperature > 30:
print("It's hot outside! 🥵")
print("Turn on the AC")
print("This runs always")
# Output: It's hot outside! 🥵
# Output: Turn on the AC
# Output: This runs always
battery = 15
if battery < 20:
print("⚠️ Low battery!")
print("Please charge your phone")
# When condition is False, nothing prints
battery = 50
if battery < 20:
print("This won't print")
# Output: ⚠️ Low battery!
# Output: Please charge your phone
💰 Money Check
money = 500
if money >= 100:
print("You can buy")
🎂 Age Check
age = 18
if age >= 18:
print("Adult")
✅ Password Check
password = "secret"
if password == "secret":
print("Access granted")
🔹 What is True? What is False?
| Values that are False | Values that are True |
|---|---|
False |
True |
0, 0.0 |
Any non-zero number: 1, -5, 3.14 |
"" (empty string) |
"hello", " ", "a" (any non-empty string) |
[] (empty list) |
[1,2,3] (any non-empty list) |
{} (empty dictionary) |
{"name":"Raj"} (non-empty dict) |
None |
Everything else! |
🎯 Visual Example: How If Works
age >= 18
age = 20 → True
Inside if block runs!
age >= 18
age = 15 → False
Inside if block SKIPPED!
🔹 Important Concepts
# ✅ Correct indentation
if True:
print("This is inside if")
print("This is also inside if")
print("This is outside if")
# ❌ Wrong indentation
if True:
print("This is inside if")
print("This will cause IndentationError!")
Multiple Statements in If:
You can put as many statements as you want inside an if block. Just keep the same indentation!
if condition:
statement1
statement2
statement3
# ... and so on
Where If Conditions Are Used:
⚖️ When to Use If
- You need to make a decision in your code
- You want to run code only under certain conditions
- You're checking user input or data
- You need to validate something
- Example:
if age >= 18: print("Adult")
⚠️ Common Mistakes
- Forgetting the colon (:) at the end of if line
- Wrong indentation: Python is strict about spaces!
- Using = instead of ==:
if x = 5:is wrong, useif x == 5: - Forgetting that if only runs when True
✏️ Quick Practice
If: Write if to check if number is positive
If: Check if name equals "Admin"
If: Check if list is not empty
📌 Quick Reference
🎉 Chapter Summary
✅ if = "If this is true, do this" - lets your program make decisions
✅ Colon (:) required after the condition
✅ Indentation shows which code belongs to the if block
✅ Code runs ONLY when condition is True
✅ Some values are automatically True/False (0, "", None are False)
✅ You can have multiple statements inside if with same indentation
5.2 If-Else with Real Example (Age, Login, etc.)
🔹 If-Else (The Two-Path Decision Maker)
If-else gives your program two paths: one for when condition is True, another for when it's False. Like a fork in the road - one path if true, another if false!
if condition:
# code runs when condition is True
else:
# code runs when condition is False
⚠️ One of the two blocks ALWAYS runs - never both!
age = 16
# Normal if-else
if age >= 18:
print("You can vote! 🗳️")
print("You can drive! 🚗")
else:
print("You're a minor 👶")
print(f"Wait {18-age} more years")
# Output: You're a minor 👶
# Output: Wait 2 more years
# Try with different age
age = 20
if age >= 18:
print("You can vote! 🗳️")
else:
print("You're a minor 👶")
# Output: You can vote! 🗳️
username = "admin"
password = "1234"
# Login check
if username == "admin" and password == "1234":
print("✅ Login successful!")
print("Welcome to dashboard")
print("Redirecting...")
else:
print("❌ Login failed")
print("Check username/password")
print("Try again")
# Output: ✅ Login successful!
# Output: Welcome to dashboard
# Output: Redirecting...
# Wrong credentials
username = "user"
if username == "admin" and password == "1234":
print("✅ Welcome admin")
else:
print("❌ Access denied")
temp = 35
if temp > 30:
print("Hot day! 🥵")
else:
print("Pleasant day 😊")
battery = 15
if battery < 20:
print("Charge now! ⚡")
else:
print("Battery OK ✅")
total = 1500
if total > 1000:
print("10% discount!")
else:
print("No discount")
🔹 Common If-Else Patterns
| Pattern | Example | When True | When False |
|---|---|---|---|
| Even/Odd | if num % 2 == 0 |
Even number | Odd number |
| Pass/Fail | if marks >= 40 |
Pass ✅ | Fail ❌ |
| Positive/Negative | if num > 0 |
Positive | Negative or Zero |
| Member/Non-member | if is_member |
Member price | Regular price |
| Empty/Non-empty | if my_list |
Has items | Empty |
🎯 Visual Example: If-Else Flow
age >= 18
age = 20 → if block runs
age = 15 → else block runs
Real-World If-Else Examples:
⚖️ When to Use If-Else
- You have two possible outcomes (binary decision)
- You need to handle both True and False cases
- You want to provide feedback for both success and failure
- Example:
if age >= 18: print("Adult") else: print("Minor") - Example:
if password_correct: grant_access() else: show_error()
⚠️ Common Mistakes
- Forgetting else for validation: Always handle the failure case!
- Wrong indentation in else: else must align with if
- Using assignment = instead of comparison ==
- Putting semicolon after condition:
if x > 5;:is wrong! - Forgetting colon after else:
else:not justelse
✏️ Quick Practice
If-Else: Check if number is positive or negative
If-Else: Check voting eligibility
If-Else: Check if string is empty
If-Else: Check even or odd
If-Else: Login success/failure
If-Else: Temperature alert
📌 Quick Reference
🎉 Chapter Summary
✅ if-else = "If true do this, else do that" - handles both paths
✅ if block runs when condition is True
✅ else block runs when condition is False
✅ One of the two blocks ALWAYS executes (never both, never none)
✅ Perfect for binary decisions: yes/no, pass/fail, adult/minor
✅ Used everywhere: login systems, age checks, validation, games
5.3 Nested Conditions Explained Slowly
🔹 Nested Conditions (If Inside If)
Nested conditions means putting one if statement inside another if statement. Like Russian dolls - conditions inside conditions! Used when you need to check multiple levels.
if condition1:
# code for condition1 True
if condition2:
# code for both True
else:
# code for condition1 True, condition2 False
else:
# code for condition1 False
⚠️ Each nested level adds one more level of indentation (4 spaces)!
marks = 85
income = 300000
sports = True
# Nested conditions - step by step check
if marks >= 80:
print("✅ Good marks")
# Nested if for income check
if income < 500000:
print("✅ Low income")
# Double nested for sports
if sports:
print("✅ Sports quota")
print("🎉 Full scholarship!")
else:
print("❌ No sports quota")
print("📚 Partial scholarship")
else:
print("❌ Income too high")
print("📚 No scholarship")
else:
print("❌ Marks too low")
# Output: ✅ Good marks
# Output: ✅ Low income
# Output: ✅ Sports quota
# Output: 🎉 Full scholarship!
has_passport = True
age = 25
has_visa = False
# Nested conditions for travel
if has_passport:
print("✅ Passport OK")
if age >= 18:
print("✅ Adult")
if has_visa:
print("✅ Visa OK")
print("🎫 Ticket confirmed!")
else:
print("❌ Need visa")
print("Apply for visa first")
else:
print("❌ Minor needs guardian")
print("Need parent permission")
else:
print("❌ Get passport first")
print("Apply at passport office")
# Output: ✅ Passport OK
# Output: ✅ Adult
# Output: ❌ Need visa
# Output: Apply for visa first
num = 10
if num > 0:
if num % 2 == 0:
print("Positive Even")
else:
print("Positive Odd")
if logged_in:
if role == "admin":
print("Admin panel")
else:
print("User panel")
if raining:
if temp < 20:
print("Cold rain ☔")
else:
print("Warm rain 🌧️")
🔹 Understanding Nested Levels
| Level | Indentation | Example | When it runs |
|---|---|---|---|
| Level 0 | No indent | if condition1: |
Always checked first |
| Level 1 | 4 spaces | if condition2: |
Runs only if condition1 is True |
| Level 2 | 8 spaces | if condition3: |
Runs only if condition1 AND condition2 are True |
| Level 3 | 12 spaces | if condition4: |
Runs only if all above are True |
🎯 Visual Example: Nested If Flow
if marks >= 80?
True ↓
if income < 500000?
True ↓
if sports?
True ↓
Full Scholarship! 🎉
Each level only runs if ALL previous conditions are True
🔹 Better Alternatives to Deep Nesting
# Hard to read!
if a:
if b:
if c:
if d:
print("Too deep!")
# Much cleaner!
if a and b and c and d:
print("Perfect!")
📝 Instead of nested if:
if user:
if password:
if age >= 18:
print("Welcome")
✨ Use and operator:
if user and password and age >= 18:
print("Welcome")
Where Nested Conditions Are Used:
⚖️ When to Use Nested Conditions
- You need to check conditions in a specific sequence
- Later checks depend on earlier ones being true
- You want different messages at each level
- You need to handle specific combinations of conditions
- Example:
if logged_in: if role == "admin": ...
⚠️ Common Mistakes
- Wrong indentation: Each nested level must indent exactly 4 spaces
- Nesting too deep: More than 3-4 levels becomes unreadable
- Forgetting else at each level: Handle all possible paths
- Mismatched if-else: else belongs to the nearest if
- Not using logical operators when possible: and/or can simplify
✏️ Quick Practice
Nested: Check if number is positive and even
Nested: Check admin and special permission
Nested: Temperature and weather check
Simplify: Convert nested to logical operator
Nested: Login with role check
Nested: Exam with attendance
📌 Quick Reference
🎉 Chapter Summary
✅ Nested conditions = if statements inside if statements
✅ Each nested level needs more indentation (4 spaces per level)
✅ Inner if runs only when ALL outer conditions are True
✅ Avoid nesting too deep (max 3-4 levels recommended)
✅ Use logical operators (and/or) to simplify deep nesting
✅ Perfect for multi-level validation like scholarships, travel, loans
5.4 Elif Statements (Multiple Conditions)
🔹 Elif (Else-If) - Multiple Conditions
Elif (short for "else if") lets you check multiple conditions in sequence. Like a multiple-choice question - it checks each option until it finds one that's True!
if condition1:
# runs if condition1 is True
elif condition2:
# runs if condition1 is False AND condition2 is True
elif condition3:
# runs if condition1,2 are False AND condition3 is True
else:
# runs if ALL conditions are False
⚠️ Only ONE block runs - the first True condition!
marks = 85
# Elif checks in order
if marks >= 90:
grade = "A+"
print("Excellent! 🌟")
elif marks >= 80:
grade = "A"
print("Very Good! 👍")
elif marks >= 70:
grade = "B"
print("Good! 👌")
elif marks >= 60:
grade = "C"
print("Average 📝")
elif marks >= 40:
grade = "D"
print("Pass ✅")
else:
grade = "F"
print("Fail ❌")
print(f"Grade: {grade}")
# Output: Very Good! 👍
# Output: Grade: A
# Try different marks:
# 95 → Excellent! 🌟, Grade: A+
# 75 → Good! 👌, Grade: B
# 35 → Fail ❌, Grade: F
hour = 14 # 2 PM
# Elif for time greeting
if hour < 12:
print("Good Morning! ☀️")
print("Time for breakfast")
elif hour < 17:
print("Good Afternoon! 🌤️")
print("Time for lunch")
elif hour < 20:
print("Good Evening! 🌆")
print("Time for dinner")
else:
print("Good Night! 🌙")
print("Time to sleep")
# Output: Good Afternoon! 🌤️
# Output: Time for lunch
# Different hours:
# 9 AM → Good Morning! ☀️, breakfast
# 2 PM → Good Afternoon! 🌤️, lunch
# 6 PM → Good Evening! 🌆, dinner
# 10 PM → Good Night! 🌙, sleep
temp = 35
if temp > 40:
print("Extreme heat!")
elif temp > 30:
print("Hot day")
elif temp > 20:
print("Pleasant")
else:
print("Cold day")
amount = 2500
if amount > 5000:
disc = 30
elif amount > 3000:
disc = 20
elif amount > 1000:
disc = 10
else:
disc = 0
battery = 15
if battery > 80:
print("🔋 Full")
elif battery > 50:
print("⚡ Good")
elif battery > 20:
print("⚠️ Medium")
else:
print("🪫 Charge now!")
🔹 How Elif Works (Step by Step)
| Condition | Checked? | When it runs |
|---|---|---|
if marks >= 90 |
1st | Only if marks >= 90 |
elif marks >= 80 |
2nd | Only if marks < 90 AND marks >= 80 |
elif marks >= 70 |
3rd | Only if marks < 80 AND marks >= 70 |
elif marks >= 60 |
4th | Only if marks < 70 AND marks >= 60 |
else |
Last | Only if ALL above are False |
🎯 Visual Example: Elif Flow
False ↓
True →
Stops at first True condition - doesn't check rest!
🔹 Important Rules of Elif
- Conditions checked in order (top to bottom)
- Stops at the first True condition
- Only ONE block runs (the first True)
- Else runs only if ALL conditions are False
- You can have as many elifs as you want
# Goes from highest to lowest
if marks >= 90:
grade = "A+"
elif marks >= 80:
grade = "A" # 85 stops here
elif marks >= 70:
grade = "B"
# Wrong! First condition catches all
if marks >= 70:
grade = "B" # 85 stops here!
elif marks >= 90:
grade = "A+" # Never runs
elif marks >= 80:
grade = "A" # Never runs
Where Elif Statements Are Used:
⚖️ When to Use Elif
- You have multiple possible conditions (more than 2)
- Conditions are mutually exclusive (only one can be true)
- You need to check conditions in a specific order
- You want different outputs for different ranges
- Example:
if marks >= 90: A+ elif marks >= 80: A elif marks >= 70: B
⚠️ Common Mistakes
- Wrong order of conditions: Check larger ranges first, then smaller
- Using multiple if instead of elif: Multiple ifs check ALL conditions
- Forgetting elif is optional: You can have just if and else
- No else at the end: Always good to handle the "none of the above" case
- Overlapping conditions: Make sure ranges don't overlap incorrectly
x = 85
# ALL conditions checked!
if x >= 80:
print("A") # Runs
if x >= 60:
print("B") # Also runs!
if x >= 40:
print("C") # Also runs!
# Output: A, B, C (all three!)
x = 85
# Stops at first True!
if x >= 80:
print("A") # Runs
elif x >= 60:
print("B") # Skipped
elif x >= 40:
print("C") # Skipped
# Output: A (only one!)
✏️ Quick Practice
Elif: Write grade for 85 marks (A:90, B:80, C:70, else F)
Elif: Temperature: >40 Hot, >30 Warm, >20 Pleasant, else Cold
Elif: Time: <12 Morning, <17 Afternoon, <20 Evening, else Night
Elif: Discount: >5000 30%, >3000 20%, >1000 10%, else 0%
Elif: Battery: >80 Full, >50 Good, >20 Medium, else Low
Order: Why is order important in elif?
📌 Quick Reference
🎉 Chapter Summary
✅ elif = else-if - checks multiple conditions in sequence
✅ Stops at the first True condition - only one block runs
✅ Conditions checked from top to bottom (order matters!)
✅ else runs only if ALL conditions are False
✅ Perfect for grading, ranges, categories, and multi-level decisions
✅ Use when you have 3+ possible outcomes (not just yes/no)
5.5 Short-Hand If & Ternary Usage
🔹 Short-Hand If (Single Line If)
Short-hand if lets you write a simple if statement in just one line. Perfect when you have just one statement to execute!
# Normal if (2 lines)
if condition:
statement
# Short-hand if (1 line)
if condition: statement
⚠️ Only use for simple, single statements!
temp = 35
# Normal if (2 lines)
if temp > 30:
print("Hot day!")
# Short-hand if (1 line)
if temp > 30: print("Hot day!")
# Multiple statements? NO!
# ❌ This won't work properly
if temp > 30: print("Hot!"); print("Very hot!")
# Output: Hot day!
battery = 15
# Normal if
if battery < 20:
print("Low battery!")
# Short-hand if
if battery < 20: print("Low battery!")
# Works with any simple statement
if battery < 20: alert = "Charge now!"
print(alert) # Charge now!
# Output: Low battery!
# Output: Charge now!
if x > 0: print("Positive")
if error: log_error()
if user == "admin": is_admin = True
🔹 Ternary Operator (Value Assignment)
value = true_value if condition else false_value
a, b = 10, 20
# Find minimum
minimum = a if a < b else b
print(f"Min: {minimum}") # Min: 10
# Find maximum
maximum = a if a > b else b
print(f"Max: {maximum}") # Max: 20
# Absolute value
num = -5
abs_num = num if num >= 0 else -num
print(f"Absolute: {abs_num}") # Absolute: 5
name = "Rahul"
age = 17
# Status message
status = "Adult" if age >= 18 else "Minor"
print(f"{name} is {status}")
# Plural handling
count = 1
message = f"{count} item" if count == 1 else f"{count} items"
print(message) # 1 item
count = 5
message = f"{count} item" if count == 1 else f"{count} items"
print(message) # 5 items
💰 Discount
final = price * 0.9 if member else price
🔐 Access Level
access = "Admin" if role == "admin" else "User"
🌙 Day/Night
time = "Day" if hour < 18 else "Night"
🔹 Advanced Ternary Usage
| Pattern | Example | Readability |
|---|---|---|
| Simple | x = a if condition else b |
✅ Very Readable |
| Nested | x = a if c1 else b if c2 else c |
⚠️ Can be confusing |
| Complex | x = func1() if c1 else func2() if c2 else func3() |
❌ Hard to read |
marks = 85
# Nested ternary (hard to read)
grade = "A" if marks >= 80 else "B" if marks >= 60 else "C" if marks >= 40 else "F"
print(f"Grade: {grade}")
# Better: Use parentheses
grade = ("A" if marks >= 80 else
"B" if marks >= 60 else
"C" if marks >= 40 else
"F")
# Still better: Use elif!
if marks >= 80: grade = "A"
elif marks >= 60: grade = "B"
elif marks >= 40: grade = "C"
else: grade = "F"
# ❌ Bad - Too complex
result = "High" if x > 100 else "Medium" if x > 50 else "Low" if x > 0 else "Zero"
# ✅ Good - Simple assignment
discount = 0.3 if is_member else 0.1
# ✅ Good - Simple conditional
status = "Active" if is_logged_in else "Inactive"
# ⚠️ OK but careful
message = f"{count} item" if count == 1 else f"{count} items"
# ❌ Bad - Function calls in ternary
result = complex_func1() if condition else complex_func2()
🎯 Visual Example: Ternary Flow
age >= 18?
"Adult"
"Minor"
status = "Adult" or "Minor"
status = "Adult" if age >= 18 else "Minor"
Where Short-Hand If & Ternary Are Used:
⚖️ When to Use Each
- You have ONE simple statement
- You're just printing or logging
- You're setting a simple flag
- No else needed
- Example:
if error: log_error()
- You need to assign a value
- You have a simple if-else
- You want compact code
- Both branches return a value
- Example:
min = a if a < b else b
⚠️ Common Mistakes
- Multiple statements in short-hand if: Use semicolons but it's messy!
- Nesting ternaries too deep: Becomes unreadable - use elif instead
- Forgetting else in ternary: Ternary MUST have both if and else parts
- Using ternary for complex logic: Stick to simple conditions only
- Overusing short-hand: Readability matters more than brevity!
✏️ Quick Practice
Short-hand: Print "Adult" if age >= 18
Ternary: Set status "Pass" if marks>=40 else "Fail"
Ternary: Find max of a and b
Ternary: "Even" if num%2==0 else "Odd"
Short-hand: Set is_admin=True if role=="admin"
Ternary: Discount 10% if member else 0%
📌 Quick Reference
🎉 Chapter Summary
✅ Short-hand if = single line if: if condition: statement
✅ Ternary operator = inline if-else: x if condition else y
✅ Use short-hand only for ONE simple statement
✅ Use ternary for simple value assignments
✅ Avoid nested ternaries - they're hard to read!
✅ Readability matters more than making code short!
🎓 Module 05 : Python Conditional Statements (If, Else, Elif) Successfully Completed
You have successfully completed this module of Python for Cybersecurity.
Keep building your expertise step by step — Learn Next Module →
🔁 Python Looping Concepts — for & while
This module teaches looping in Python: how to repeat tasks safely and effectively using for and while.
Includes simple examples, common patterns, and tips to avoid infinite loops.
6.1 While Loop – Step-by-Step Explanation
What is a While Loop?
A while loop is like a repeating if statement. It keeps executing a block of code as long as a condition remains True. Think of it like a microwave that keeps beeping until you open the door!
while condition:
# code to repeat
# (must eventually make condition False)
⚠️ The indentation (4 spaces) is VERY important - it defines what's inside the loop!
# Initialize counter
i = 1
# Loop while i <= 5
while i <= 5:
print(f"Count: {i}")
i += 1 # CRITICAL: update counter!
print("Loop finished!")
# Output:
# Count: 1
# Count: 2
# Count: 3
# Count: 4
# Count: 5
# Loop finished!
✅ i += 1 prevents infinite loop
# Countdown from 5 to 1
countdown = 5
while countdown > 0:
print(f"{countdown}...")
countdown -= 1 # Decrease counter
print("🎉 Blast off!")
# Output:
# 5...
# 4...
# 3...
# 2...
# 1...
# 🎉 Blast off!
✅ Decreasing counter works too!
total = 0
i = 1
while i <= 5:
total += i
i += 1
print(f"Sum: {total}") # Sum: 15
n = 5
i = 1
while i <= 10:
print(f"{n} x {i} = {n*i}")
i += 1
i = 2
while i <= 10:
print(i)
i += 2 # Jump by 2
🔹 Infinite Loops (The Danger!)
| Code | Problem | Result |
|---|---|---|
i = 1 |
Counter never increases | INFINITE LOOP! 💀 |
i = 5 |
Counter goes wrong way | INFINITE LOOP! 💀 |
i = 1 |
Proper counter update | Runs 5 times ✅ |
🎯 Visual Example: How While Loop Works
| Step | Action | Code | Next |
|---|---|---|---|
| 1 | Start | i = 1 |
|
| 2 | Check Condition | i <= 5? |
True → False → Exit |
| 3 | Execute | print(i) |
|
| 4 | Update Counter | i += 1 |
Back to Check |
| 5 | Exit | # Loop ends |
📝 Example Run (i from 1 to 5):
i=1 ≤5? ✓print(1)
i=2
i=2 ≤5? ✓print(2)
i=3
i=3 ≤5? ✓print(3)
i=4
i=4 ≤5? ✓print(4)
i=5
i=5 ≤5? ✓print(5)
i=6
i=6 ≤5? ✗Loop ends
🔹 While Loop with User Input
# Secret password game
secret = "python"
attempt = ""
tries = 0
while attempt != secret:
attempt = input("Guess the password: ")
tries += 1
if attempt != secret:
print("❌ Wrong! Try again.")
print(f"✅ Correct! You took {tries} tries.")
# This loop continues UNTIL they guess correctly
# Number of iterations unknown in advance!
# Add numbers until user enters 0
total = 0
num = 1 # Start with non-zero
print("Enter numbers to add (0 to stop):")
while num != 0:
num = int(input("Enter number: "))
total += num
print(f"Total sum: {total}")
# Example run:
# Enter 5 → total = 5
# Enter 3 → total = 8
# Enter 0 → loop stops, total = 8
🔹 Menu System (Real-World Example)
# Restaurant Menu System
choice = 0
while choice != 5:
print("\n" + "="*30)
print(" RESTAURANT MENU")
print("="*30)
print("1. 🍕 Pizza - ₹199")
print("2. 🍔 Burger - ₹99")
print("3. 🍝 Pasta - ₹149")
print("4. 🥗 Salad - ₹79")
print("5. 🚪 Exit")
print("="*30)
choice = int(input("Enter your choice (1-5): "))
if choice == 1:
print("✅ You ordered Pizza - ₹199")
elif choice == 2:
print("✅ You ordered Burger - ₹99")
elif choice == 3:
print("✅ You ordered Pasta - ₹149")
elif choice == 4:
print("✅ You ordered Salad - ₹79")
elif choice == 5:
print("👋 Thank you! Visit again!")
else:
print("❌ Invalid choice! Please try again.")
# Menu keeps showing until user chooses 5
🔹 Loop Control: break and continue
# Stop when number is 5
i = 1
while i <= 10:
if i == 5:
print("Found 5! Stopping...")
break # Exit loop NOW!
print(i)
i += 1
print("Loop ended")
# Output:
# 1
# 2
# 3
# 4
# Found 5! Stopping...
# Loop ended
# (6-10 never printed!)
# Print only odd numbers
i = 0
while i < 10:
i += 1
if i % 2 == 0: # If even
continue # Skip rest of loop
print(i) # Only odds printed
# Output:
# 1
# 3
# 5
# 7
# 9
🔹 While-Else (Python Special!)
# Without break - else runs
i = 1
while i <= 3:
print(f"Loop {i}")
i += 1
else:
print("✅ Loop completed normally!")
# Output:
# Loop 1
# Loop 2
# Loop 3
# ✅ Loop completed normally!
# With break - else SKIPS
i = 1
while i <= 5:
if i == 3:
print("Break at 3!")
break
print(f"Loop {i}")
i += 1
else:
print("This won't print!")
# Output:
# Loop 1
# Loop 2
# Break at 3!
🔹 Nested While Loops (Loop Inside Loop)
# Multiplication table 1-3
i = 1
while i <= 3:
print(f"\nTable of {i}:")
j = 1
while j <= 5:
print(f"{i} x {j} = {i*j}")
j += 1
i += 1
# Output:
# Table of 1:
# 1 x 1 = 1
# 1 x 2 = 2
# ...
# Table of 2:
# 2 x 1 = 2
# 2 x 2 = 4
# ...
Where While Loops Are Used:
⚖️ While vs For - When to Use Which?
- You DON'T know how many iterations
- Waiting for user input/condition
- Menu systems and games
- Until something becomes True/False
- Example:
while not game_over: - Example:
while user != "quit":
- You KNOW how many iterations
- Looping through sequences (lists, strings)
- Counting from 1 to N
- Processing each item in collection
- Example:
for i in range(10): - Example:
for item in list:
⚠️ Common Mistakes
- Forgetting to update counter:
i += 1missing → infinite loop! - Wrong condition:
while i > 0with i increasing → never False - Off-by-one errors:
while i <= 5vswhile i < 5(runs 4 times) - Using = instead of ==:
while i = 5(assignment) instead ofwhile i == 5 - Infinite loop with break: Forgetting break condition in complex logic
✏️ Quick Practice
1. Print 1 to 10 using while
2. Print 10 down to 1
3. Sum of 1 to 100
4. Print only even numbers 2-20
5. Keep asking until user enters 'yes'
6. Factorial of 5 (5!)
📌 Quick Reference
🎉 Chapter Summary
✅ while loop = repeats while condition is True
✅ ALWAYS update counter inside loop to avoid infinite loops
✅ Use when number of iterations unknown (user input, games)
✅ break = exit loop immediately, continue = skip current iteration
✅ while-else runs only if loop ends normally (not by break)
✅ Great for menus, password attempts, and waiting for conditions
✅ Infinite loops are dangerous - always ensure condition becomes False!
6.2 For Loop – Iterating Easily
What is a For Loop?
A for loop is like an automatic conveyor belt that picks up each item from a collection, one by one, and lets you work with it. Perfect when you know what you want to loop through!
for variable in sequence:
# code to execute for each item
# (indented with 4 spaces)
⚠️ The variable takes the value of each item in the sequence, one at a time!
# List of fruits
fruits = ["apple", "banana", "mango", "orange", "grapes"]
for fruit in fruits:
print(f"I like {fruit}")
print("All fruits printed!")
# Output:
# I like apple
# I like banana
# I like mango
# I like orange
# I like grapes
# All fruits printed!
✅ Loop runs once for each item in the list
# String is a sequence of characters
word = "PYTHON"
for letter in word:
print(f"Letter: {letter}")
print("Loop finished!")
# Output:
# Letter: P
# Letter: Y
# Letter: T
# Letter: H
# Letter: O
# Letter: N
# Loop finished!
✅ Strings are sequences too - each character becomes an item!
colors = ("red", "green", "blue")
for color in colors:
print(color)
numbers = [10, 20, 30, 40]
for num in numbers:
print(num * 2)
student = {"name": "Raj", "age": 20}
for key in student:
print(f"{key}: {student[key]}")
🔹 The range() Function (Number Generator)
| Syntax | Example | Output | Explanation |
|---|---|---|---|
range(stop) |
range(5) |
0, 1, 2, 3, 4 | From 0 to stop-1 |
range(start, stop) |
range(1, 6) |
1, 2, 3, 4, 5 | From start to stop-1 |
range(start, stop, step) |
range(1, 10, 2) |
1, 3, 5, 7, 9 | Count by step |
range(10, 0, -1) |
range(10, 0, -1) |
10, 9, 8, ..., 1 | Count backwards! |
for i in range(1, 6):
print(i)
# 1,2,3,4,5
for i in range(5, 0, -1):
print(i)
# 5,4,3,2,1
for i in range(2, 11, 2):
print(i)
# 2,4,6,8,10
🔹 Advanced For Loop Techniques
fruits = ["apple", "banana", "mango"]
for index, fruit in enumerate(fruits):
print(f"{index + 1}. {fruit}")
# Output:
# 1. apple
# 2. banana
# 3. mango
# With custom start
for i, fruit in enumerate(fruits, start=1):
print(f"Item {i}: {fruit}")
names = ["Rahul", "Priya", "Amit"]
scores = [85, 92, 78]
for name, score in zip(names, scores):
print(f"{name}: {score}")
# Output:
# Rahul: 85
# Priya: 92
# Amit: 78
# With three lists
subjects = ["Math", "Science", "English"]
for name, score, subject in zip(names, scores, subjects):
print(f"{name} scored {score} in {subject}")
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
for num in numbers:
if num == 5:
print("Found 5! Stopping...")
break
print(num)
# Output:
# 1
# 2
# 3
# 4
# Found 5! Stopping...
# Print only odd numbers
for num in range(1, 11):
if num % 2 == 0:
continue # Skip even numbers
print(num)
# Output:
# 1
# 3
# 5
# 7
# 9
# else runs only if loop completes (no break)
numbers = [1, 2, 3, 4, 5]
for num in numbers:
if num == 6:
print("Found 6!")
break
else:
print("6 not found in the list")
# Output: 6 not found in the list
# With break - else won't run
for num in numbers:
if num == 3:
print("Found 3!")
break
else:
print("This won't print")
🔹 Real-World Applications
# Calculate average of marks
marks = [85, 90, 78, 92, 88]
total = 0
for mark in marks:
total += mark
average = total / len(marks)
print(f"Total: {total}")
print(f"Average: {average}")
# Find highest mark
highest = marks[0]
for mark in marks:
if mark > highest:
highest = mark
print(f"Highest: {highest}")
cart = [
{"item": "Shirt", "price": 499},
{"item": "Jeans", "price": 899},
{"item": "Shoes", "price": 1299},
{"item": "Hat", "price": 299}
]
total = 0
print("Your Cart:")
for product in cart:
print(f" {product['item']}: ₹{product['price']}")
total += product['price']
print(f"Total: ₹{total}")
if total > 1000:
print("You get free shipping!")
# Search for a name in list
students = ["Rahul", "Priya", "Amit", "Neha", "Raj"]
search = "Amit"
found = False
for student in students:
if student == search:
found = True
print(f"✅ Found {search}!")
break
if not found:
print(f"❌ {search} not found")
# Count occurrences
numbers = [1, 2, 3, 2, 4, 2, 5]
count = 0
for num in numbers:
if num == 2:
count += 1
print(f"Number 2 appears {count} times")
# Filter and transform data
temperatures = [23, 28, 32, 25, 30, 22, 26]
hot_days = 0
for temp in temperatures:
if temp > 30:
hot_days += 1
print(f"🔥 {temp}°C is hot!")
elif temp > 25:
print(f"👍 {temp}°C is pleasant")
else:
print(f"❄️ {temp}°C is cool")
print(f"Hot days: {hot_days}")
🔹 Nested For Loops (Loop Inside Loop)
# Multiplication table 1-3
print("Multiplication Tables:")
for i in range(1, 4):
print(f"\nTable of {i}:")
for j in range(1, 11):
print(f" {i} x {j} = {i*j}")
# Output:
# Table of 1:
# 1 x 1 = 1
# 1 x 2 = 2
# ...
# 2D List (Matrix)
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
print("\nMatrix:")
for row in matrix:
for num in row:
print(num, end=" ")
print() # New line after each row
🔹 List Comprehension (Advanced Shortcut)
squares = []
for i in range(1, 6):
squares.append(i ** 2)
print(squares) # [1, 4, 9, 16, 25]
squares = [i ** 2 for i in range(1, 6)]
print(squares) # [1, 4, 9, 16, 25]
# With condition
evens = [i for i in range(1, 11) if i % 2 == 0]
print(evens) # [2, 4, 6, 8, 10]
Where For Loops Are Used:
⚖️ For Loop vs While Loop
- You know what you're iterating through
- Working with sequences (lists, strings, etc.)
- You need to process each item in a collection
- You know the number of iterations (range)
- Example:
for item in shopping_list: - Example:
for i in range(10):
- You don't know how many iterations
- Waiting for a condition to change
- User input validation
- Menu systems and games
- Example:
while not game_over: - Example:
while user_input != "quit":
⚠️ Common Mistakes
- Modifying list while iterating: Can cause skipped items or errors
- Forgetting colon at end:
for i in range(5)❌ missing : - Wrong indentation: Code outside loop should not be indented
- Off-by-one errors with range:
range(5)gives 0-4, not 1-5 - Using same variable name inside nested loops: Causes confusion
✏️ Quick Practice
1. Print each letter of "PYTHON"
2. Sum of numbers 1 to 10
3. Print even numbers 2-20
4. Find largest in [45, 67, 23, 89, 12]
5. Count how many 'a' in "banana"
6. Print multiplication table of 7
📌 Quick Reference
🎉 Chapter Summary
✅ for loop = iterate through sequences (lists, strings, range)
✅ range(stop) = 0 to stop-1, range(start, stop) = start to stop-1, range(start, stop, step) = with step
✅ enumerate() = get index and value together
✅ zip() = loop through multiple lists simultaneously
✅ break = exit loop, continue = skip current iteration
✅ for-else runs only if loop completes (no break)
✅ Perfect for processing collections, calculations, and repetitive tasks
6.3 Loop with else (Hidden Python Feature)
What is Loop-else?
Both for and while loops in Python have a hidden superpower – an optional
else block that runs ONLY when the loop completes normally (without hitting a break statement).
It's like a "completion certificate" for your loop!
# For loop with else
for item in sequence:
if condition:
# found what we need
break
else:
# runs only if NO break occurred
# While loop with else
while condition:
if something:
break
else:
# runs only if loop ended naturally
# (condition became False without break)
⚠️ This is Python-specific - most languages don't have this feature!
- If they find an open door (break), they stop checking and call security.
- If all rooms are checked and no open door found (else), they report "All secure!"
# Search for a number in a list
numbers = [2, 4, 6, 8, 10]
search_for = 5
print(f"Searching for {search_for}...")
for num in numbers:
print(f"Checking: {num}")
if num == search_for:
print(f"✅ Found {search_for}!")
break
else:
print(f"❌ {search_for} not found in list")
print("Search complete.")
# Output:
# Searching for 5...
# Checking: 2
# Checking: 4
# Checking: 6
# Checking: 8
# Checking: 10
# ❌ 5 not found in list
# Search complete.
✅ else runs because loop completed all iterations without break
# Search for a number that exists
numbers = [2, 4, 6, 8, 10]
search_for = 6
print(f"Searching for {search_for}...")
for num in numbers:
print(f"Checking: {num}")
if num == search_for:
print(f"✅ Found {search_for}!")
break
else:
print(f"❌ {search_for} not found") # This WON'T run!
print("Search complete.")
# Output:
# Searching for 6...
# Checking: 2
# Checking: 4
# Checking: 6
# ✅ Found 6!
# Search complete.
# Notice: else block did NOT execute!
❌ else skipped because break terminated the loop early
🔹 While Loop with Else
# Countdown with early interruption
count = 5
interrupted = False
while count > 0:
print(f"Count: {count}")
if count == 3 and interrupted:
print("Interrupted at 3!")
break
count -= 1
else:
print("✅ Countdown completed normally!")
# Without interruption:
# Count: 5
# Count: 4
# Count: 3
# Count: 2
# Count: 1
# ✅ Countdown completed normally!
# Player lives system
lives = 3
game_over = False
while lives > 0 and not game_over:
print(f"Playing... {lives} lives left")
# Simulate losing a life
lives -= 1
if lives == 1:
print("⚠️ Last life!")
if lives == 0:
break # Game over
else:
print("🎉 You won! Completed all levels!")
# If player loses all lives (break occurs):
# else block WON'T run
# If player completes game (loop ends naturally):
# else block runs with victory message!
🔹 Classic Example: Prime Number Check
# Check if a number is prime
def is_prime(n):
"""Check if n is a prime number using loop-else"""
if n <= 1:
return False
for i in range(2, int(n ** 0.5) + 1):
if n % i == 0:
print(f"{n} is divisible by {i}")
return False # Exit function (like break)
else:
# This runs if no divisor found!
print(f"No divisors found for {n}")
return True
# Test some numbers
numbers = [17, 24, 37, 42, 53]
for num in numbers:
result = is_prime(num)
print(f"{num} is prime: {result}\n")
# Output for 17:
# No divisors found for 17
# 17 is prime: True
# Output for 24:
# 24 is divisible by 2
# 24 is prime: False
🔹 When Does Else Run?
| Scenario | Loop Type | What Happens | Else Runs? |
|---|---|---|---|
| Loop completes all iterations | for/while | All items processed, condition becomes False | ✅ YES |
Loop hits break |
for/while | Exit early, remaining iterations skipped | ❌ NO |
Loop hits return (in function) |
for/while | Function exits entirely | ❌ NO |
| Loop raises exception | for/while | Error occurs, loop stops | ❌ NO |
| Empty sequence | for | Loop never runs (no iterations) | ✅ YES |
| Condition initially False | while | Loop never enters | ✅ YES |
🎯 Visual Example: Loop-else Flow
(No break)
(break occurred)
Loop completed without break
break occurred
for i in range(5):
if i == 3:
break # else won't run
else:
print("No break occurred")
🔹 Real-World Applications
# Process payment attempts
payment_methods = [
{"type": "credit", "balance": 500},
{"type": "debit", "balance": 300},
{"type": "wallet", "balance": 100}
]
amount = 200
for method in payment_methods:
print(f"Trying {method['type']} card...")
if method['balance'] >= amount:
print(f"✅ Payment successful with {method['type']}!")
break
else:
print("❌ All payment methods failed!")
print("Please use another payment method")
# If payment succeeds with credit card:
# else block won't run
# If all cards have insufficient balance:
# else runs with failure message
# Try connecting to servers
servers = ["server1.com", "server2.com", "server3.com"]
connected = False
for server in servers:
print(f"Attempting to connect to {server}...")
# Simulate connection attempt
if server == "server2.com": # Assume this works
print(f"✅ Connected to {server}!")
connected = True
break
else:
print("❌ Could not connect to any server")
print("Check your internet connection")
if connected:
print("You are now online!")
# This pattern is common in:
# - Load balancers
# - Database connection pools
# - API fallback systems
🔹 Nested Loops with Else
else belongs to the loop it's attached to!
# Find a number in a 2D matrix
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
search = 10
found = False
print(f"Searching for {search} in matrix:")
for row in matrix:
print(f"Checking row: {row}")
for num in row:
print(f" Checking number: {num}")
if num == search:
print(f" ✅ Found {search}!")
found = True
break # breaks inner loop only
else:
# Inner loop else - runs if no break in inner loop
print(" Row complete - number not in this row")
continue # continue outer loop
# This runs if inner loop broke
break # break outer loop
if not found:
print(f"❌ {search} not found anywhere!")
# The else after inner loop tells us when a row is fully searched
# without finding the target
🔹 Common Misconceptions
- "else runs when condition is False"
- "else is like an if-else for loops"
- "else runs when loop doesn't execute"
- "else runs when loop errors"
- ✅ else runs when loop completes ALL iterations
- ✅ else is a "no-break" detector
- ✅ else runs for empty sequences too!
- ✅ else is Python's unique feature
⚖️ When to Use Loop-Else
- Search operations (found/not found)
- Prime number checking
- Validation loops
- Fallback mechanisms
- When you need "no break" detection
- Cleaner than flag variables
- Code readability suffers
- Team members don't know this feature
- Simple loops where flag is clearer
- Complex nested loops
- Without comments explaining usage
🔹 Alternative: Using Flag Variables
for item in items:
if condition(item):
print("Found")
break
else:
print("Not found")
found = False
for item in items:
if condition(item):
print("Found")
found = True
break
if not found:
print("Not found")
Where Loop-Else Is Used:
⚠️ Common Mistakes
- Thinking else runs when loop doesn't execute: Actually, else runs when loop completes - even if it's empty!
- Misplacing else in nested loops: else attaches to the loop it's immediately after
- Using else with continue: continue doesn't affect else - only break matters!
- Not commenting the else block: Can confuse other programmers
- Forgetting that return also prevents else: In functions, return exits before else
✏️ Quick Practice
1. Check if all numbers in list are positive
2. Check if string has any uppercase
3. Check if number is prime using loop-else
4. Does else run if loop never executes?
5. Convert to loop-else: found flag
6. Password attempt with max tries
📌 Quick Reference
🎉 Chapter Summary
✅ loop-else = Python's unique feature that runs when loop completes without break
✅ Works with both for and while loops
✅ Perfect for "search and confirm" patterns
✅ break, return, or exceptions PREVENT else from running
✅ Even runs if loop never executes (empty sequence)
✅ Use with comments to avoid confusing others
✅ Alternative to flag variables - cleaner in many cases!
6.4 Nested Loops (Loops inside Loops)
What are Nested Loops?
A nested loop is a loop inside another loop. Think of it like a clock - the minute hand (inner loop) completes a full cycle for every tick of the hour hand (outer loop). This creates powerful combinations for working with 2D data!
for outer_var in outer_sequence:
# Outer loop code
for inner_var in inner_sequence:
# Inner loop code - runs completely
# for EACH iteration of outer loop
# More outer loop code (after inner loop)
⚠️ The inner loop runs ALL its iterations for EVERY single outer loop iteration!
- Outer loop: Days of the week (Monday to Friday)
- Inner loop: Class periods (Period 1, 2, 3, 4, 5, 6)
- For EACH day, you go through ALL periods!
# Print multiplication table 1-3
print("Multiplication Table (1-3):")
print("-" * 25)
for i in range(1, 4): # Outer loop - rows
for j in range(1, 4): # Inner loop - columns
# end=" " keeps output on same line
print(f"{i} x {j} = {i*j:2d}", end=" ")
print() # New line after each row
print() # Blank line for spacing
# Output:
# Multiplication Table (1-3):
# -------------------------
# 1 x 1 = 1 1 x 2 = 2 1 x 3 = 3
#
# 2 x 1 = 2 2 x 2 = 4 2 x 3 = 6
#
# 3 x 1 = 3 3 x 2 = 6 3 x 3 = 9
✅ Inner loop runs 3 times for each outer loop iteration (total 9 iterations)
# Print a right-angled triangle
size = 5
print("Triangle Pattern:")
print("-" * 20)
for i in range(1, size + 1): # Outer: rows
for j in range(i): # Inner: columns
print("*", end=" ")
print() # New line after each row
# Output:
# Triangle Pattern:
# --------------------
# *
# * *
# * * *
# * * * *
# * * * * *
# The inner loop runs i times - first row 1 star,
# second row 2 stars, etc.
🔹 Working with 2D Lists (Matrices)
# Create and display a 3x3 matrix
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
print("3x3 Matrix:")
print("-" * 15)
for row in matrix: # Outer: each row
for value in row: # Inner: each element in row
print(f"{value:3d}", end=" ")
print() # New line after row
# Output:
# 3x3 Matrix:
# ---------------
# 1 2 3
# 4 5 6
# 7 8 9
# Calculate sum of all elements
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
total = 0
row_count = len(matrix)
col_count = len(matrix[0])
for i in range(row_count): # Outer: rows
for j in range(col_count): # Inner: columns
total += matrix[i][j]
print(f"Adding matrix[{i}][{j}] = {matrix[i][j]}")
print(f"Running total: {total}\n")
print(f"Final sum: {total}") # 45
# Find maximum element in matrix
matrix = [
[12, 45, 23],
[67, 34, 89],
[21, 56, 78]
]
max_value = matrix[0][0]
max_pos = (0, 0)
print("Searching for maximum...")
print("-" * 30)
for i in range(len(matrix)):
for j in range(len(matrix[i])):
current = matrix[i][j]
print(f"Checking [{i}][{j}] = {current}")
if current > max_value:
print(f" ✅ New max found! {current} > {max_value}")
max_value = current
max_pos = (i, j)
print("-" * 30)
print(f"Maximum value: {max_value}")
print(f"Found at position: {max_pos}")
# Output shows the search process step by step
🔹 Pattern Printing Gallery
rows, cols = 4, 6
for i in range(rows):
for j in range(cols):
print("*", end="")
print()
# Output:
# ******
# ******
# ******
# ******
n = 5
for i in range(n):
# Spaces
for j in range(n - i - 1):
print(" ", end="")
# Stars
for j in range(2 * i + 1):
print("*", end="")
print()
# Output:
# *
# ***
# *****
# *******
# *********
n = 4
# Top half
for i in range(n):
print(" " * (n - i - 1) + "*" * (2 * i + 1))
# Bottom half
for i in range(n - 2, -1, -1):
print(" " * (n - i - 1) + "*" * (2 * i + 1))
# Output:
# *
# ***
# *****
# *******
# *****
# ***
# *
🔹 Understanding Loop Count
| Outer Loop | Inner Loop | Total Iterations | Example |
|---|---|---|---|
| 3 iterations | 4 iterations each | 3 × 4 = 12 | for i in range(3): for j in range(4): |
| 5 iterations | 5 iterations each | 5 × 5 = 25 | Multiplication table 5×5 |
| n iterations | n iterations each | n² (O(n²)) | Processing n×n matrix |
| n iterations | i iterations (varies) | n(n+1)/2 | Triangle pattern (1+2+3+...+n) |
🎯 Visual Example: Nested Loop Execution
Inner j=1 Inner j=2 Inner j=3 Inner j=4
Inner j=1 Inner j=2 Inner j=3 Inner j=4
For i=1 to 3: inner loop runs j=1 to 4 for EACH i
🔹 Break and Continue in Nested Loops
break and continue only affect the innermost loop they're in!
for i in range(1, 4):
print(f"Row {i}: ", end="")
for j in range(1, 6):
if j == 3:
break # Stops ONLY inner loop
print(j, end=" ")
print() # Outer loop continues!
# Output:
# Row 1: 1 2
# Row 2: 1 2
# Row 3: 1 2
for i in range(1, 4):
print(f"Row {i}: ", end="")
for j in range(1, 6):
if j == 3:
continue # Skip ONLY this iteration
print(j, end=" ")
print()
# Output:
# Row 1: 1 2 4 5
# Row 2: 1 2 4 5
# Row 3: 1 2 4 5
# How to break out of BOTH loops
found = False
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
search = 5
for i in range(len(matrix)):
if found:
break
for j in range(len(matrix[i])):
if matrix[i][j] == search:
print(f"Found {search} at position [{i}][{j}]")
found = True
break # breaks inner loop
# Outer loop checks 'found' and breaks if True
# Alternative: Use for-else (see 6.3)
🔹 Real-World Applications
# Simple month calendar
days_in_month = 31
start_day = 2 # Tuesday (0=Monday, 6=Sunday)
print(" M T W T F S S")
print("-" * 21)
# Print initial spaces
for i in range(start_day):
print(" ", end="")
# Print days
for day in range(1, days_in_month + 1):
print(f"{day:3d}", end="")
if (start_day + day) % 7 == 0:
print() # New line after Sunday
# Tic-Tac-Toe board display
board = [
['X', 'O', 'X'],
['O', 'X', 'O'],
['X', 'O', 'X']
]
print("Tic-Tac-Toe Board:")
print("-" * 13)
for i in range(3):
print("|", end="")
for j in range(3):
print(f" {board[i][j]} |", end="")
print("\n" + "-" * 13)
# Output:
# Tic-Tac-Toe Board:
# -------------
# | X | O | X |
# -------------
# | O | X | O |
# -------------
# | X | O | X |
# -------------
# Temperature readings (3 cities × 4 time slots)
temps = [
[22, 24, 23, 21], # City 1
[18, 20, 19, 17], # City 2
[25, 27, 26, 24] # City 3
]
print("Temperature Readings:")
print("City\t6am\t12pm\t6pm\t12am")
for i, city in enumerate(temps):
print(f"City {i+1}", end="")
for temp in city:
print(f"\t{temp}°C", end="")
print()
# Calculate average per city
print("\nAverages:")
for i, city in enumerate(temps):
total = sum(city)
avg = total / len(city)
print(f"City {i+1}: {avg:.1f}°C")
# Print chessboard pattern
size = 8
for i in range(size):
for j in range(size):
if (i + j) % 2 == 0:
print("⬜", end="")
else:
print("⬛", end="")
print()
# Output:
# ⬜⬛⬜⬛⬜⬛⬜⬛
# ⬛⬜⬛⬜⬛⬜⬛⬜
# ⬜⬛⬜⬛⬜⬛⬜⬛
# ⬛⬜⬛⬜⬛⬜⬛⬜
# ...
🔹 Performance Considerations
| Data Size (n) | Operations (n²) | Time (approx) |
|---|---|---|
| 10 | 100 | Instant |
| 100 | 10,000 | Fast |
| 1,000 | 1,000,000 | Noticeable |
| 10,000 | 100,000,000 | Several seconds |
| 1,000,000 | 1,000,000,000,000 | Years! |
Where Nested Loops Are Used:
✏️ Quick Practice
1. Print 3×3 square of numbers 1-9
2. Print pattern: 1, 12, 123, 1234
3. Find sum of all elements in 3×3 matrix
4. Print multiplication table up to 5×5
5. Print hollow square of * with size 5
6. Transpose a 3×3 matrix
📌 Quick Reference
🎉 Chapter Summary
✅ Nested loops = loops inside loops - inner loop runs completely for each outer iteration
✅ Essential for 2D data (matrices, grids, tables)
✅ Great for pattern printing and combinations
✅ Total iterations = outer × inner (O(n²) complexity)
✅ break/continue only affect the innermost loop
✅ Used in games, image processing, calendars, and data analysis
✅ Warning: Can be slow with large data - use carefully!
6.5 Understanding range() Function
What is the range() Function?
The range() function is Python's number generator. It produces a sequence of numbers
without storing them all in memory at once. Think of it as a smart counter that creates numbers
on demand – perfect for loops!
range(stop) # 0 to stop-1
range(start, stop) # start to stop-1
range(start, stop, step) # start to stop-1, increment by step
⚠️ stop is exclusive (not included), step can be negative!
- range(5): Tickets 0,1,2,3,4 (5 tickets)
- range(1,5): Tickets 1,2,3,4 (start at 1)
- range(1,10,2): Tickets 1,3,5,7,9 (every 2nd ticket)
# One argument: range(stop)
print("range(5):", list(range(5))) # [0, 1, 2, 3, 4]
# Two arguments: range(start, stop)
print("range(2, 7):", list(range(2, 7))) # [2, 3, 4, 5, 6]
# Three arguments: range(start, stop, step)
print("range(1, 10, 2):", list(range(1, 10, 2))) # [1, 3, 5, 7, 9]
# Step can be negative
print("range(10, 0, -2):", list(range(10, 0, -2))) # [10, 8, 6, 4, 2]
# Zero step? ERROR!
# range(1, 10, 0) # ValueError: step cannot be zero!
# Counting down
print("Countdown from 5:")
for i in range(5, 0, -1):
print(f"{i}...")
print("Blast off! 🚀")
# Backwards with custom step
print("\nEven numbers backwards:")
print(list(range(20, 0, -2))) # [20, 18, 16, ..., 2]
# Important: start > stop when step is negative
# This works: range(10, 0, -1)
# This gives empty: range(0, 10, -1) - start < stop with negative step
print("\nEmpty range:")
print(list(range(0, 10, -1))) # [] - empty!
🔹 Complete range() Reference Table
| Function Call | Start | Stop | Step | Result (as list) | Use Case |
|---|---|---|---|---|---|
range(5) |
0 | 5 | 1 (default) | [0, 1, 2, 3, 4] | Loop 5 times |
range(1, 5) |
1 | 5 | 1 (default) | [1, 2, 3, 4] | Start at 1 |
range(1, 10, 2) |
1 | 10 | 2 | [1, 3, 5, 7, 9] | Odd numbers |
range(2, 11, 2) |
2 | 11 | 2 | [2, 4, 6, 8, 10] | Even numbers |
range(10, 0, -1) |
10 | 0 | -1 | [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] | Countdown |
range(5, 0, -2) |
5 | 0 | -2 | [5, 3, 1] | Odd countdown |
range(0, -10, -2) |
0 | -10 | -2 | [0, -2, -4, -6, -8] | Negative numbers |
range(5, 1) |
5 | 1 | 1 | [] (empty) | Start > stop with positive step = empty |
🎯 Visual Example: How range() Works
0 to 4 (5 numbers)
2 to 6 (5 numbers)
Odd numbers 1,3,5,7,9
Green = numbers generated, Gray = boundaries (stop value not included)
🔹 Advanced Features & Properties
# range is memory-efficient!
r = range(1000000)
print(f"Size of range: {r.__sizeof__()} bytes")
# About 48 bytes regardless of size!
# Compare with list
l = list(range(1000000))
print(f"Size of list: {l.__sizeof__()} bytes")
# Millions of bytes!
# range generates numbers on demand
for i in range(1000000):
if i % 100000 == 0:
print(f"Processing {i}... (still efficient)")
# This won't crash memory!
r = range(2, 10, 2)
# range has these properties
print(f"Start: {r.start}") # 2
print(f"Stop: {r.stop}") # 10
print(f"Step: {r.step}") # 2
# Check if value exists
print(f"4 in r: {4 in r}") # True
print(f"5 in r: {5 in r}") # False
# Indexing works like list
print(f"r[0]: {r[0]}") # 2
print(f"r[1]: {r[1]}") # 4
print(f"r[-1]: {r[-1]}") # 8 (last element)
# Length
print(f"Length: {len(r)}") # 4
🔹 Common Use Cases
# Repeat something 5 times
for i in range(5):
print(f"Iteration {i}")
# Your code here
fruits = ["apple", "banana", "mango"]
for i in range(len(fruits)):
print(f"{i+1}. {fruits[i]}")
# Every 3rd number
for i in range(0, 20, 3):
print(i, end=" ")
# 0 3 6 9 12 15 18
# Multiple ways to reverse
print("Method 1: reversed()")
for i in reversed(range(5)):
print(i, end=" ")
# 4 3 2 1 0
print("\nMethod 2: negative step")
for i in range(4, -1, -1):
print(i, end=" ")
# 4 3 2 1 0
print("\nMethod 3: convert to list")
for i in list(range(5))[::-1]:
print(i, end=" ")
# 4 3 2 1 0
# Multiplication table
for i in range(1, 4):
for j in range(1, 4):
print(f"{i} x {j} = {i*j}")
print()
# Coordinate grid
for x in range(3):
for y in range(3):
print(f"({x},{y})", end=" ")
print()
# (0,0) (0,1) (0,2)
# (1,0) (1,1) (1,2)
# (2,0) (2,1) (2,2)
🔹 Python 2 vs Python 3
range() returned a list (memory intensive), and xrange() was the memory-efficient version.
In Python 3, range() works like Python 2's xrange() - memory efficient by default!
# Python 2 - BAD for large ranges!
r = range(1000000) # Creates huge list
# Uses millions of bytes!
# Python 2 - GOOD
r = xrange(1000000) # Memory efficient
# But xrange doesn't exist in Python 3!
# Python 3 - ALWAYS memory efficient!
r = range(1000000) # Memory efficient
# Uses only ~48 bytes!
# No need for xrange - range does it all
# Best of both worlds!
🔹 Converting range to Other Types
| Conversion | Code | Result |
|---|---|---|
| To List | list(range(5)) |
[0, 1, 2, 3, 4] |
| To Tuple | tuple(range(5)) |
(0, 1, 2, 3, 4) |
| To Set | set(range(5)) |
{0, 1, 2, 3, 4} |
| To String | str(range(5)) |
"range(0, 5)" (not numbers!) |
🔹 Real-World Applications
# Generate monthly report data
months = range(1, 13)
month_names = ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
print("Monthly Sales Report")
print("-" * 30)
for month_num in months:
month_name = month_names[month_num - 1]
# Simulate sales data
sales = month_num * 1000
print(f"{month_name}: ₹{sales:,}")
print("-" * 30)
print(f"Total: ₹{sum(month_num * 1000 for month_num in months):,}")
# Display items with pagination
items = list(range(1, 101)) # 100 items
items_per_page = 10
total_pages = len(items) // items_per_page
current_page = 2 # Show page 2
start = (current_page - 1) * items_per_page
end = start + items_per_page
print(f"Page {current_page} of {total_pages}")
print("-" * 30)
for i in range(start, end):
print(f"Item {items[i]}")
print("-" * 30)
print("Previous 1 2 3 4 5 ... Next")
⚠️ Common Mistakes
- Off-by-one errors:
range(5)gives 0-4, NOT 1-5! - Empty ranges:
range(5, 1)is empty (start > stop with positive step) - Step cannot be zero:
range(1, 10, 0)raises ValueError - Forgetting range is exclusive:
range(1, 5)doesn't include 5 - Using range with float: range only works with integers!
✏️ Quick Practice
1. Generate numbers 0 to 9
2. Generate 5,6,7,8,9
3. Generate odd numbers 1,3,5,7,9
4. Generate 10,8,6,4,2
5. What's wrong: range(1.5, 5.5)?
6. Sum of 1 to 100 using range
📌 Quick Reference
🎉 Chapter Summary
✅ range(stop) = 0 to stop-1 (step=1)
✅ range(start, stop) = start to stop-1 (step=1)
✅ range(start, stop, step) = start to stop-1 with custom step
✅ Memory efficient - generates numbers on demand, doesn't store them all
✅ Step can be negative for reverse counting
✅ Works with integers only - no floats!
✅ Use list(range()) to see the actual numbers
🎓 Module 06 : Python Looping Concept (for & while) Successfully Completed
You have successfully completed this module of Python for Cybersecurity.
Keep building your expertise step by step — Learn Next Module →
⛔ Control Statements in Python – break, continue & pass
Control statements are special instructions that help you control the flow of loops. They allow you to stop a loop, skip a loop step, or do nothing temporarily.
7.1 break Statement – Stop the Loop Immediately
What is the break Statement?
The break statement is like an emergency exit for your loops. It allows you to
exit a loop instantly, regardless of whether the loop condition is still True. Once Python hits a
break, it immediately jumps out of the loop and continues with the code after it.
# In for loop
for item in sequence:
if condition:
break # Exit loop immediately
# code here won't run after break
# In while loop
while condition:
if some_condition:
break # Exit loop immediately
# code here won't run after break
⚠️ When break executes, the loop ends RIGHT THERE - no further iterations!
- You check drawer 1 → no keys
- You check drawer 2 → no keys
- You check drawer 3 → FOUND KEYS! → You stop checking (break!)
- You don't check drawers 4 and 5
# Searching for a specific number
numbers = [1, 3, 5, 7, 9, 11, 13, 15]
search_for = 7
print(f"Searching for {search_for}...")
print("-" * 30)
for n in numbers:
print(f"Checking: {n}")
if n == search_for:
print(f"✅ Found {search_for}! Stopping search.")
break # Exit loop immediately
print(f" {n} is not what we're looking for")
print("-" * 30)
print("Search completed!")
# Output:
# Searching for 7...
# ------------------------------
# Checking: 1
# 1 is not what we're looking for
# Checking: 3
# 3 is not what we're looking for
# Checking: 5
# 5 is not what we're looking for
# Checking: 7
# ✅ Found 7! Stopping search.
# ------------------------------
# Search completed!
# (11, 13, 15 are never checked!)
✅ break saves time by stopping early once found
# Same search WITHOUT break
numbers = [1, 3, 5, 7, 9, 11, 13, 15]
search_for = 7
print(f"Searching for {search_for}...")
print("-" * 30)
found = False
for n in numbers:
print(f"Checking: {n}")
if n == search_for:
print(f"✅ Found {search_for}!")
found = True
# No break - continues anyway!
print("-" * 30)
if found:
print("Found it, but wasted time!")
else:
print("Not found")
# Output keeps checking ALL numbers
# even after finding 7 - WASTEFUL!
❌ Without break, loop continues unnecessarily
🔹 break in Different Loop Types
# Stop when we reach 50
total = 0
for i in range(1, 101):
total += i
if total > 50:
print(f"Stopped at i={i}, total={total}")
break
print(f"Final total: {total}")
# Output:
# Stopped at i=10, total=55
# Final total: 55
# (Didn't need to go to 100!)
# Menu system with break
while True: # Infinite loop
choice = input("Enter command (quit to exit): ")
if choice == "quit":
print("Goodbye!")
break # Exit the infinite loop
print(f"You entered: {choice}")
# The loop runs until user types "quit"
# break provides the exit condition!
🔹 Real-World Applications
# Login system with 3 attempts
max_attempts = 3
attempt = 1
while attempt <= max_attempts:
print(f"\nAttempt {attempt} of {max_attempts}")
username = input("Username: ")
password = input("Password: ")
if username == "admin" and password == "secret":
print("✅ Login successful!")
break # Exit loop on success
else:
print("❌ Invalid credentials")
attempt += 1
else:
# This runs if loop ends without break
print("⛔ Account locked. Too many failed attempts.")
# break exits immediately on success
# No need to try more attempts!
# Simple treasure hunt game
import random
treasure_location = random.randint(1, 10)
print("Treasure hunt! Guess number 1-10")
for guess_count in range(1, 6): # 5 attempts
guess = int(input(f"Guess {guess_count}: "))
if guess == treasure_location:
print(f"🎉 You found the treasure in {guess_count} tries!")
break # Game ends on success
elif guess < treasure_location:
print("🔽 Too low, try again")
else:
print("🔼 Too high, try again")
else:
# No break means all attempts used
print(f"💀 Game over! Treasure was at {treasure_location}")
# break ends the game early on success
# Try multiple payment methods
payment_methods = [
{"type": "Credit Card", "available": 500},
{"type": "Debit Card", "available": 300},
{"type": "Wallet", "available": 100},
{"type": "Gift Card", "available": 50}
]
amount = 250
payment_successful = False
for method in payment_methods:
print(f"Trying {method['type']}...")
if method['available'] >= amount:
print(f"✅ Payment successful with {method['type']}!")
payment_successful = True
break # Stop trying more methods
else:
print(f"❌ Insufficient balance in {method['type']}")
if not payment_successful:
print("❌ All payment methods failed!")
# break prevents trying remaining methods after success
# Check if data contains errors
data = [34, 67, 23, -5, 89, 12, 56]
has_error = False
for index, value in enumerate(data):
if value < 0:
print(f"❌ Error found at position {index}: negative value {value}")
has_error = True
break # Stop checking after first error
if not has_error:
print("✅ All values are valid")
else:
print("🔧 Please fix the error and try again")
# break saves time by stopping at first error
# No need to check remaining data
🔹 break in Nested Loops
break only exits the innermost loop it's in, not all loops!
# break only exits inner loop
for i in range(1, 4):
print(f"\nRow {i}:", end=" ")
for j in range(1, 6):
if j == 3:
print(f"break at j={j}", end=" ")
break # Exits ONLY inner loop
print(j, end=" ")
print("← outer loop continues!")
# Output:
# Row 1: 1 2 break at j=3 ← outer loop continues!
# Row 2: 1 2 break at j=3 ← outer loop continues!
# Row 3: 1 2 break at j=3 ← outer loop continues!
# How to break out of ALL loops
found = False
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
search = 5
for i in range(len(matrix)):
if found:
break
for j in range(len(matrix[i])):
if matrix[i][j] == search:
print(f"Found {search} at [{i}][{j}]")
found = True
break # breaks inner loop
# Outer loop checks flag and breaks
# Alternative: Use for-else with nested loops
# But flag method is clearer!
# Using a function to break all loops cleanly
def search_matrix(matrix, target):
"""Search matrix and return position if found"""
for i in range(len(matrix)):
for j in range(len(matrix[i])):
if matrix[i][j] == target:
return (i, j) # Returns immediately, exits ALL loops!
return None # Not found
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
result = search_matrix(matrix, 5)
if result:
i, j = result
print(f"Found at position [{i}][{j}]")
else:
print("Not found")
# Using return is cleaner than complex flag logic!
🔹 break and else Together
else runs ONLY if loop completes without break!
# Search with break and else
numbers = [2, 4, 6, 8, 10]
search = 5
for num in numbers:
if num == search:
print(f"✅ Found {search}")
break
else:
print(f"❌ {search} not found")
# Output: ❌ 5 not found
# else runs because break never executed
# When break happens, else SKIPS
numbers = [2, 4, 6, 8, 10]
search = 6
for num in numbers:
if num == search:
print(f"✅ Found {search}")
break
else:
print(f"❌ {search} not found") # Won't run!
# Output: ✅ Found 6
# else does NOT run because break executed
🔹 Using break with Infinite Loops
while True + break = "Run until something happens"
# Common pattern: while True with break
print("Simple Calculator (type 'quit' to exit)")
while True: # Run forever (until break)
print("\n" + "="*30)
user_input = input("Enter expression (or 'quit'): ")
if user_input.lower() == 'quit':
print("Goodbye!")
break # Exit the infinite loop
try:
result = eval(user_input)
print(f"Result: {result}")
except:
print("Invalid expression!")
print("Calculator closed.")
# This pattern is used in:
# - Menu systems
# - Game loops
# - Server listeners
# - Interactive programs
while True:
print("\n1. Play")
print("2. Settings")
print("3. Quit")
choice = input("Choice: ")
if choice == "3":
print("Thanks for playing!")
break
# handle other choices
while True:
data = get_sensor_data()
if data is None: # No more data
break
process_data(data)
🔹 When to Use break
| Scenario | Why Use break | Example |
|---|---|---|
| 🔍 Search | Stop searching after finding item | if item == target: break |
| ✅ Validation | Stop at first error | if not valid: break |
| 🎮 Games | Exit game loop on win/loss | if game_over: break |
| 🔐 Login | Stop after successful login | if login_success: break |
| 📊 Data Processing | Stop when condition met | if total > limit: break |
| 🔄 Infinite Loops | Provide exit condition | while True: ... if quit: break |
🔹 break vs return vs exit()
- Exits ONLY the current loop
- Continues with code after loop
- Loop-specific
- Exits the ENTIRE function
- Returns a value to caller
- Exits all loops in function
- Exits the ENTIRE program
- Stops Python completely
- Use sparingly!
⚠️ Common Mistakes
- break outside loop: Using
breakwhen not in a loop causes SyntaxError - break in nested loops: Forgetting it only exits inner loop
- break vs continue confusion: break exits, continue skips to next iteration
- break in if-else: break must be inside a loop, not just in if
- Missing break condition: Infinite loop if condition never met
✏️ Quick Practice
1. Stop loop when number 7 found in [2,4,7,9]
2. Keep asking until user types 'quit'
3. Stop summing when total exceeds 100
4. Find first negative number in list
5. Login with 3 attempts using break
6. Break out of nested loops (hard)
📌 Quick Reference
🎉 Chapter Summary
✅ break = emergency exit for loops - stops immediately
✅ Used for search operations (stop when found)
✅ Essential for infinite loops (while True + break)
✅ In nested loops, break only exits the innermost loop
✅ break vs else: else runs only if no break occurred
✅ Common in: login systems, games, menus, validation
✅ break saves time by stopping early when job is done
7.2 continue Statement – Skip to Next Iteration
🔹 What is the continue Statement?
The continue statement is like a "skip this one" command for your loops. When Python hits a
continue, it immediately jumps to the next iteration of the loop, skipping any remaining code
in the current iteration. It doesn't exit the loop – it just moves on to the next item!
# In for loop
for item in sequence:
if condition_to_skip:
continue # Skip rest of this iteration
# code here runs only if continue wasn't triggered
# In while loop
while condition:
if something:
continue # Jump back to check condition again
# code here runs only if continue wasn't triggered
⚠️ continue skips the CURRENT iteration only – loop continues with next item!
- Passenger 1: has ID → proceed
- Passenger 2: no ID → skip (continue)! Don't check bags
- Passenger 3: has ID → proceed
- Continue means "skip this one, move to next"
# Print only odd numbers
print("Odd numbers from 1 to 10:")
print("-" * 30)
for i in range(1, 11):
if i % 2 == 0:
continue # Skip even numbers
print(f"Odd number: {i}")
print("-" * 30)
print("Loop completed!")
# Output:
# Odd numbers from 1 to 10:
# ------------------------------
# Odd number: 1
# Odd number: 3
# Odd number: 5
# Odd number: 7
# Odd number: 9
# ------------------------------
# Loop completed!
✅ continue skips evens, only odds get printed
# Process non-empty names
names = ["Rahul", "", "Priya", "", "Amit", "Neha", ""]
print("Valid names:")
print("-" * 30)
for name in names:
if not name: # Skip empty strings
continue
print(f"✅ {name}")
print("-" * 30)
print(f"Total names: {len(names)}")
print(f"Valid names processed: {sum(1 for n in names if n)}")
# Output:
# Valid names:
# ------------------------------
# ✅ Rahul
# ✅ Priya
# ✅ Amit
# ✅ Neha
# ------------------------------
# Total names: 7
# Valid names processed: 4
✅ continue filters out invalid data
🔹 continue in Different Loop Types
# Process only items meeting criteria
items = [1, -2, 3, -4, 5, -6, 7, -8, 9]
print("Processing positive numbers:")
for num in items:
if num < 0:
print(f" Skipping negative: {num}")
continue # Skip negatives
print(f"✅ Processing positive: {num}")
# Output shows processing of positives only
# While loop with continue
i = 0
while i < 10:
i += 1
if i % 3 == 0:
print(f" Skipping {i} (multiple of 3)")
continue # Skip multiples of 3
print(f"Processing {i}")
# Output:
# Processing 1
# Processing 2
# Skipping 3
# Processing 4
# Processing 5
# Skipping 6
# ...
🔹 Real-World Applications
# Clean and process survey data
responses = [
{"name": "Rahul", "age": 25, "score": 85},
{"name": "", "age": 30, "score": 92}, # Invalid name
{"name": "Priya", "age": -5, "score": 78}, # Invalid age
{"name": "Amit", "age": 22, "score": 95},
{"name": "Neha", "age": 28, "score": -10} # Invalid score
]
valid_count = 0
invalid_count = 0
for response in responses:
# Skip invalid entries
if not response["name"]:
invalid_count += 1
print(f"❌ Skipping: Missing name")
continue
if response["age"] <= 0 or response["age"] > 120:
invalid_count += 1
print(f"❌ Skipping: Invalid age for {response['name']}")
continue
if response["score"] < 0 or response["score"] > 100:
invalid_count += 1
print(f"❌ Skipping: Invalid score for {response['name']}")
continue
# Process valid data
valid_count += 1
print(f"✅ Processing: {response['name']}, Age: {response['age']}, Score: {response['score']}")
print(f"\nSummary: {valid_count} valid, {invalid_count} invalid entries")
# Process customer orders, skip unavailable items
menu = {
"pizza": {"price": 199, "available": True},
"burger": {"price": 99, "available": False},
"pasta": {"price": 149, "available": True},
"salad": {"price": 79, "available": False},
"sandwich": {"price": 89, "available": True}
}
customer_order = ["pizza", "burger", "pasta", "salad", "sandwich", "icecream"]
total = 0
processed = []
print("Processing your order...")
print("-" * 40)
for item in customer_order:
if item not in menu:
print(f"❌ {item} - Not on menu (skipped)")
continue
if not menu[item]["available"]:
print(f"⏳ {item} - Currently unavailable (skipped)")
continue
# Item is available - process it
price = menu[item]["price"]
total += price
processed.append(item)
print(f"✅ {item} - ₹{price} added to cart")
print("-" * 40)
print(f"Ordered items: {', '.join(processed)}")
print(f"Total bill: ₹{total}")
# Process log file, skip comment lines
log_lines = [
"INFO: Server started",
"# This is a comment",
"ERROR: Connection failed",
"",
"WARNING: High memory usage",
"# DEBUG: This is debug info",
"INFO: Request processed"
]
print("Processing log entries:")
print("-" * 30)
for line_num, line in enumerate(log_lines, 1):
# Skip empty lines
if not line.strip():
print(f"Line {line_num}: [EMPTY - skipped]")
continue
# Skip comments
if line.startswith("#"):
print(f"Line {line_num}: [COMMENT - skipped]")
continue
# Process actual log entries
print(f"Line {line_num}: {line}")
print("-" * 30)
print("Log processing complete!")
# Filter stocks based on criteria
stocks = [
{"symbol": "AAPL", "price": 175, "volume": 1000000},
{"symbol": "GOOG", "price": 2800, "volume": 500000},
{"symbol": "TSLA", "price": 0, "volume": 2000000}, # Invalid price
{"symbol": "MSFT", "price": 330, "volume": -1000}, # Invalid volume
{"symbol": "AMZN", "price": 125, "volume": 1500000},
{"symbol": "", "price": 50, "volume": 800000} # Invalid symbol
]
print("Analyzing stocks...")
print("-" * 40)
for stock in stocks:
# Skip invalid symbols
if not stock["symbol"]:
print("❌ Invalid symbol - skipped")
continue
# Skip invalid prices
if stock["price"] <= 0:
print(f"❌ {stock['symbol']}: Invalid price {stock['price']} - skipped")
continue
# Skip invalid volumes
if stock["volume"] <= 0:
print(f"❌ {stock['symbol']}: Invalid volume {stock['volume']} - skipped")
continue
# Analyze valid stocks
value = stock["price"] * stock["volume"]
print(f"✅ {stock['symbol']}: Market cap ₹{value:,}")
print("-" * 40)
print("Analysis complete!")
🔹 continue in Nested Loops
continue only affects the innermost loop it's in!
# Skip certain values in inner loop only
for i in range(1, 4):
print(f"\nRow {i}:", end=" ")
for j in range(1, 6):
if j == 3:
print(f"skip", end=" ")
continue # Skips ONLY inner loop iteration
print(j, end=" ")
print("← outer loop continues normally")
# Output:
# Row 1: 1 2 skip 4 5 ← outer loop continues
# Row 2: 1 2 skip 4 5 ← outer loop continues
# Row 3: 1 2 skip 4 5 ← outer loop continues
# Skip entire rows based on condition
for i in range(1, 6):
if i % 2 == 0:
print(f"\nSkipping entire row {i}")
continue # Skips the whole row!
print(f"\nRow {i}:", end=" ")
for j in range(1, 4):
print(j, end=" ")
# Output:
# Row 1: 1 2 3
# Skipping entire row 2
# Row 3: 1 2 3
# Skipping entire row 4
# Row 5: 1 2 3
🔹 continue vs break – Key Differences
| Feature | continue |
break |
|---|---|---|
| Effect | Skips current iteration only | Exits the entire loop |
| Loop after | Continues with next iteration | Loop stops completely |
| Analogy | Skip one item, check next | Stop checking altogether |
| Use case | Filtering unwanted data | Found what you're looking for |
| Code after loop | Always runs | Always runs |
for i in range(1, 6):
if i == 3:
continue # Skip 3
print(i, end=" ")
# Output: 1 2 4 5
for i in range(1, 6):
if i == 3:
break # Stop at 3
print(i, end=" ")
# Output: 1 2
🔹 When to Use continue
| Scenario | Why Use continue | Example |
|---|---|---|
| 🔢 Skip even/odd numbers | Process only numbers matching criteria | if num % 2 == 0: continue |
| 🧹 Data cleaning | Skip invalid/empty entries | if not data: continue |
| 🚫 Filter out values | Ignore unwanted items | if item in blacklist: continue |
| 📝 Skip comments in files | Process only actual data lines | if line.startswith('#'): continue |
| ✅ Validation | Process only valid items | if not is_valid(x): continue |
| 🎮 Game logic | Skip inactive players | if not player.active: continue |
🔹 continue and else
continue does NOT affect loop-else – else still runs if loop completes all iterations!
# continue doesn't prevent else from running
print("Example 1: With continue")
for i in range(1, 6):
if i == 3:
print(f" Skipping {i}")
continue
print(f"Processing {i}")
else:
print("✅ Loop completed normally (else runs)")
print("\nExample 2: With break (for comparison)")
for i in range(1, 6):
if i == 3:
print(f" Breaking at {i}")
break
print(f"Processing {i}")
else:
print("❌ This else won't run")
# continue allows else to run, break prevents it!
⚠️ Common Mistakes
- continue outside loop: Using
continuewhen not in a loop causes SyntaxError - continue in nested loops: Forgetting it only affects the innermost loop
- Unreachable code after continue: Code after continue in same block never runs
- continue in while loop without increment: Can cause infinite loop!
- Confusing continue with break: continue skips one iteration, break exits completely
# ❌ DANGEROUS - Infinite loop!
i = 0
while i < 5:
if i == 3:
continue # BUG: i never increments!
print(i)
i += 1
# ✅ CORRECT - Always increment before continue
i = 0
while i < 5:
i += 1 # Increment FIRST
if i == 3:
continue
print(i)
✏️ Quick Practice
1. Print numbers 1-10, skip multiples of 3
2. Process list, skip empty strings
3. Print only words longer than 3 letters
4. Print all except 'admin'
5. Sum positive numbers, skip negatives
6. Skip vowels in a string
📌 Quick Reference
🎉 Chapter Summary
✅ continue = "skip this one, move to next" – skips current iteration only
✅ Perfect for filtering data – process only what you want
✅ In while loops, be careful to increment before continue
✅ continue vs break: continue skips one, break stops all
✅ continue doesn't affect else – else still runs if loop completes
✅ Used for: data cleaning, validation, skipping comments, filtering
✅ continue makes code cleaner than nested if-else
7.3 pass Statement – Do Nothing Placeholder
🔹 What is the pass Statement?
The pass statement is Python's way of saying "do nothing". It's a placeholder
that tells Python, "I know this code needs to be here, but I'm not ready to write it yet." Unlike continue
which skips to the next iteration, pass literally does absolutely nothing!
# In functions
def function_name():
pass # Function body coming soon
# In classes
class MyClass:
pass # Class definition coming soon
# In loops
for item in sequence:
pass # Loop body coming soon
# In conditionals
if condition:
pass # Handle this case later
else:
# real code here
⚠️ pass is NOT a comment – it's actual Python code that does nothing!
- Empty storefront with sign → pass (placeholder for future business)
- Comment would be like a note on the door
passis the actual empty space waiting to be filled
# Planning future features
def calculate_tax(amount):
"""TODO: Implement tax calculation"""
pass # Will implement later
def send_email(to, subject, body):
"""TODO: Add email functionality"""
pass # Coming in next version
def process_payment(card_number, amount):
"""TODO: Integrate payment gateway"""
pass # Waiting for API access
# These functions can be called but do nothing
calculate_tax(1000) # No error, just does nothing
send_email("user@example.com", "Hi", "Hello") # Silent
process_payment("1234-5678", 500) # Placeholder
print("All functions called successfully (they just did nothing)")
✅ Functions with pass can be called without errors
# Planning class hierarchy
class Animal:
"""Base class for all animals"""
pass # Will add common attributes later
class Mammal(Animal):
"""Mammals inherit from Animal"""
pass # TODO: Add mammal-specific features
class Bird(Animal):
"""Birds inherit from Animal"""
pass # TODO: Add bird-specific features
# These classes exist but have no methods/attributes yet
dog = Mammal() # Creates an empty object
eagle = Bird() # Also empty
print(f"Created: {type(dog).__name__}")
print(f"Created: {type(eagle).__name__}")
# We can even add attributes dynamically
dog.name = "Buddy"
print(f"Dog's name: {dog.name}")
✅ Classes with pass can still be instantiated
🔹 pass in Loops
# Loop that does nothing (but counts)
print("Loop starting...")
for i in range(1, 6):
pass # Loop runs but does nothing
print("Loop completed 5 iterations silently")
# More practical: placeholder for future processing
items = ["apple", "banana", "mango"]
for item in items:
# TODO: Add validation logic later
pass # Just iterates through items
print(f"Processed {len(items)} items (with no actual processing)")
# pass vs continue - VERY different!
print("Using pass:")
for i in range(1, 4):
if i == 2:
pass # Does nothing, continues normally
print(f"Value: {i}")
# Output: 1, 2, 3 (all values printed)
print("\nUsing continue:")
for i in range(1, 4):
if i == 2:
continue # Skips rest of iteration
print(f"Value: {i}")
# Output: 1, 3 (2 is skipped)
# pass = "do nothing, move on"
# continue = "skip rest of THIS iteration"
🔹 pass in If-Else Statements
# Placeholder for specific conditions
def check_number(num):
"""Check if number meets certain criteria"""
if num > 100:
# TODO: Handle large numbers later
pass # Will implement complex logic
elif num < 0:
print(f"Number {num} is negative")
else:
print(f"Number {num} is between 0 and 100")
# Test the function
check_number(150) # Does nothing (pass)
check_number(-5) # Prints: Number -5 is negative
check_number(50) # Prints: Number 50 is between 0 and 100
print("\n" + "="*50)
# Stub for menu options
def show_menu():
print("\n1. View Profile")
print("2. Edit Settings")
print("3. Logout")
choice = input("Enter choice: ")
if choice == "1":
# TODO: Implement profile view
pass
elif choice == "2":
# TODO: Implement settings editor
pass
elif choice == "3":
print("Goodbye!")
else:
print("Invalid choice!")
print("Menu system ready (options 1 and 2 coming soon)")
🔹 Real-World Development Scenarios
# Development in progress
class UserManager:
"""User management system (in development)"""
def create_user(self, username, password):
"""Create new user account"""
# TODO: Add password hashing
# TODO: Add validation
# TODO: Check for duplicates
pass # Implementation coming soon
def delete_user(self, user_id):
"""Remove user from system"""
# TODO: Add confirmation
# TODO: Clean up user data
pass # Will implement later
def update_profile(self, user_id, **kwargs):
"""Update user information"""
# TODO: Validate fields
# TODO: Log changes
pass # Coming in version 2.0
def get_user_stats(self):
"""Get user statistics"""
# Simple placeholder that returns something
return {"total": 0, "active": 0}
# We can still use completed parts
manager = UserManager()
stats = manager.get_user_stats()
print(f"Current stats: {stats}")
print("Other methods coming soon!")
# Creating API structure before implementation
class PaymentGateway:
"""Payment gateway integration (stub version)"""
def __init__(self, api_key):
self.api_key = api_key
# Initialize later
pass
def process_credit_card(self, card, amount):
"""Process credit card payment"""
# TODO: Integrate with payment API
# TODO: Handle errors
# TODO: Return transaction ID
pass
def process_upi(self, upi_id, amount):
"""Process UPI payment"""
# TODO: Implement UPI
pass
def refund(self, transaction_id):
"""Process refund"""
# TODO: Add refund logic
pass
def get_transaction_status(self, transaction_id):
"""Check transaction status"""
# Placeholder returning dummy data
return {"status": "pending", "message": "Stub response"}
# Client can start integration
gateway = PaymentGateway("test_key_123")
status = gateway.get_transaction_status("txn_001")
print(f"API Response: {status}")
print("Payment methods coming soon!")
🔹 pass in Exception Handling
# Sometimes you want to ignore specific errors
try:
num = int(input("Enter a number: "))
result = 10 / num
print(f"Result: {result}")
except ValueError:
# Ignore invalid number input
pass # Silently ignore
except ZeroDivisionError:
# Ignore division by zero
pass # Silently ignore
print("Program continues regardless of errors")
# ⚠️ WARNING: This is usually BAD practice!
# Better to at least log the error
# Better pattern - log then pass
import logging
try:
risky_operation()
except Exception as e:
# Log the error for debugging
logging.error(f"Error occurred: {e}")
# Still pass - don't crash the program
pass
# Even better with TODO
try:
# Some risky code
pass
except FileNotFoundError:
# TODO: Create missing file automatically
pass # Will implement later
except PermissionError:
# TODO: Ask user for permissions
pass # Coming in next version
🔹 pass vs Comment vs continue
| Feature | pass |
Comment (#) | continue |
|---|---|---|---|
| What it does | Nothing (but valid code) | Ignored by Python | Skips to next iteration |
| When Python sees it | Executes (does nothing) | Ignores completely | Jumps to next loop iteration |
| Can it be in empty block? | ✅ Yes (required!) | ❌ No (syntax error) | ❌ No (needs loop) |
| Use case | Placeholder for future code | Documentation | Skipping items |
| Example | if x: pass |
if x: # TODO |
if x: continue |
if True:
pass # Does nothing
print("Runs")
if True:
# TODO
print("Runs")
for i in range(1):
if True:
continue
print("No")
🔹 When pass is REQUIRED
# Empty function - ERROR!
def my_function():
# SyntaxError: unexpected EOF
# Empty class - ERROR!
class MyClass:
# SyntaxError
# Empty if block - ERROR!
if condition:
# SyntaxError
# Empty function - WORKS!
def my_function():
pass
# Empty class - WORKS!
class MyClass:
pass
# Empty if block - WORKS!
if condition:
pass
🔹 Best Practices
- Creating empty functions/classes for future implementation
- Stubbing out APIs during development
- Writing code top-down (placeholders first)
- Creating abstract base classes
- When syntax requires a statement but you're not ready
- With TODO comments to mark incomplete code
- You actually want to skip something (use continue)
- You want to exit a loop (use break)
- You want to ignore errors silently (at least log!)
- In production code without TODO comments
- When a comment would be more appropriate
⚠️ Common Mistakes
- Using pass when you need continue: pass doesn't skip iterations!
- Forgetting pass in empty block: Python requires at least one statement
- Overusing pass: Empty blocks in production code are confusing
- Not adding TODO comments: Others won't know it's incomplete
- Using pass to ignore exceptions silently: Always log at least!
- Pass vs ... (ellipsis): ... is another placeholder, but less common
✏️ Quick Practice
1. Create empty function named "future_feature"
2. Create empty class named "DatabaseConnection"
3. If statement with pass placeholder
4. Loop that runs but does nothing
5. Try-except with pass
6. Why can't we just use comments?
📌 Quick Reference
🎉 Chapter Summary
✅ pass = "nothing here yet" – a placeholder that does absolutely nothing
✅ Required for empty functions, classes, and blocks (syntax requirement)
✅ pass vs continue: pass does nothing and continues, continue skips to next iteration
✅ Development tool – perfect for top-down programming and stubs
✅ Always add TODO comments with pass to mark incomplete code
✅ Used in exception handling to temporarily ignore errors (but log them!)
✅ pass is code – unlike comments, it actually executes (doing nothing)
7.4 Real-Life Loop Control Examples
🔹 Putting It All Together
Now that we've learned break, continue, and loop-else separately, let's see how they work together in
real-world scenarios. These examples show how loop control statements create powerful, efficient programs!
password = "1234"
attempts = ["1111", "2222", "", "1234", "9999", "0000"]
print("🔐 Login System Started")
print("-" * 40)
for attempt_num, attempt in enumerate(attempts, 1):
print(f"\nAttempt {attempt_num}: '{attempt}'")
if attempt == "":
print(" ⏭️ Empty input detected - skipping (continue)")
continue # Skip empty inputs
if attempt == password:
print(f" ✅ CORRECT! Access granted!")
break # Exit loop on success
else:
print(f" ❌ Wrong password")
else:
# This runs only if no break occurred
print("\n❌❌❌ ALL ATTEMPTS FAILED! Account locked.")
print("-" * 40)
print("Login process complete")
# Output shows:
# - Empty input is skipped (continue)
# - Wrong passwords continue
# - Correct password triggers break
# - Loop-else runs only if no success
🔹 Example 1: ATM Machine Simulation
# ATM Transaction System
balance = 5000
pin = "1234"
max_attempts = 3
transactions = [1000, -200, 500, -1000, 2000, -500, 300]
print("🏦 ATM MACHINE SIMULATION")
print("=" * 50)
# PIN Verification (using break and else)
print("STEP 1: PIN Verification")
print("-" * 30)
for attempt in range(1, max_attempts + 1):
entered_pin = input(f"Attempt {attempt}/{max_attempts} - Enter PIN: ")
if not entered_pin: # Empty input
print(" ⏭️ Empty PIN - try again")
continue
if entered_pin == pin:
print("✅ PIN verified successfully!")
break
else:
print(f"❌ Wrong PIN. {max_attempts - attempt} attempts left")
else:
print("⛔ TOO MANY FAILED ATTEMPTS! Card blocked.")
print("Please contact your bank.")
# Exit early - don't proceed to transactions
# We'll simulate with a flag
verified = False
# Process transactions (only if PIN verified)
if 'verified' in locals() or entered_pin == pin:
print("\nSTEP 2: Processing Transactions")
print("-" * 30)
for trans_num, amount in enumerate(transactions, 1):
print(f"\nTransaction {trans_num}: ₹{amount}")
# Skip zero transactions (just in case)
if amount == 0:
print(" ⏭️ Zero transaction - skipping")
continue
# Check for withdrawal vs deposit
if amount < 0: # Withdrawal
withdraw = abs(amount)
if withdraw > balance:
print(f" ❌ Insufficient balance! Available: ₹{balance}")
continue # Skip this transaction, try next
else:
balance -= withdraw
print(f" 💸 Withdrawal: ₹{withdraw}")
print(f" New balance: ₹{balance}")
else: # Deposit
balance += amount
print(f" 💰 Deposit: ₹{amount}")
print(f" New balance: ₹{balance}")
# Check if balance is getting low
if balance < 1000:
print(f" ⚠️ LOW BALANCE WARNING: ₹{balance}")
# Emergency stop if balance becomes negative (shouldn't happen)
if balance < 0:
print(" 🚨 CRITICAL ERROR: Negative balance!")
print(" Stopping all transactions.")
break
else:
# All transactions processed successfully
print("\n✅ All transactions completed successfully!")
print("\n" + "=" * 50)
print(f"Final balance: ₹{balance}")
else:
print("\n❌ Cannot process transactions - PIN verification failed.")
# Summary of control statements used:
# - continue: skip empty PIN, zero transactions, insufficient funds
# - break: stop after correct PIN, emergency stop on negative balance
# - for-else: all transactions processed successfully
🔹 Example 2: Student Grading System
# Student Exam Processing System
students = [
{"name": "Rahul", "marks": [85, 90, 78, -5, 92]}, # Invalid mark
{"name": "Priya", "marks": [72, 68, 85, 91, 88]},
{"name": "Amit", "marks": [95, 87, 93, 99, 96]},
{"name": "Neha", "marks": [45, 52, 38, 61, 49]}, # Low marks
{"name": "Raj", "marks": []} # No marks
]
passing_marks = 40
distinction = 75
results = []
print("📚 STUDENT GRADE PROCESSING SYSTEM")
print("=" * 60)
for student_num, student in enumerate(students, 1):
print(f"\n{'='*40}")
print(f"Processing Student {student_num}: {student['name']}")
print(f"{'='*40}")
# Skip students with no marks
if not student['marks']:
print(f"⏭️ No marks available - skipping {student['name']}")
continue
total = 0
subject_count = 0
has_failed = False
for subject_num, marks in enumerate(student['marks'], 1):
print(f" Subject {subject_num}: {marks}")
# Skip invalid marks
if marks < 0 or marks > 100:
print(f" ⏭️ Invalid marks ({marks}) - skipping")
continue
# Check if student failed this subject
if marks < passing_marks:
print(f" ❌ Failed (below {passing_marks})")
has_failed = True
# Don't break - still need to calculate total for passed subjects
total += marks
subject_count += 1
# Skip if no valid subjects
if subject_count == 0:
print(f"⏭️ No valid subjects for {student['name']}")
continue
# Calculate average
average = total / subject_count
# Determine grade
if has_failed:
grade = "F (Failed one or more subjects)"
results.append((student['name'], grade, average, "❌"))
continue # Skip further processing for failed students
# Process passed students
if average >= distinction:
grade = "A (Distinction)"
remarks = "🌟 Excellent!"
elif average >= 60:
grade = "B (First Class)"
remarks = "👍 Good job!"
elif average >= passing_marks:
grade = "C (Pass)"
remarks = "✅ You passed"
results.append((student['name'], grade, average, remarks))
# Check if any student scored 100% (perfect score)
if average == 100:
print(f"\n🏆 PERFECT SCORE! {student['name']} got 100%")
# Not breaking - still want to process others
print("\n" + "=" * 60)
print("📊 FINAL RESULTS SUMMARY")
print("=" * 60)
for name, grade, average, remarks in results:
print(f"\n{name}:")
print(f" Average: {average:.1f}%")
print(f" Grade: {grade}")
print(f" {remarks}")
print("\n" + "=" * 60)
# Control statements used:
# - continue: skip invalid marks, failed students
# - continue: skip students with no marks
# - break: not used here (would stop processing all students)
# - continue allows processing all students while skipping problematic data
🔹 Example 3: E-Commerce Shopping Cart
# E-Commerce Order Processing System
inventory = [
{"item": "Laptop", "price": 45000, "stock": 5},
{"item": "Mouse", "price": 500, "stock": 0}, # Out of stock
{"item": "Keyboard", "price": 1500, "stock": 3},
{"item": "Monitor", "price": 12000, "stock": 2},
{"item": "USB Cable", "price": 200, "stock": 0}, # Out of stock
{"item": "Headphones", "price": 2500, "stock": 4}
]
shopping_cart = [
{"item": "Laptop", "quantity": 1},
{"item": "Mouse", "quantity": 2},
{"item": "Keyboard", "quantity": 1},
{"item": "USB Cable", "quantity": 3},
{"item": "Tablet", "quantity": 1} # Not in inventory
]
customer_balance = 50000
order_total = 0
order_items = []
out_of_stock_items = []
not_found_items = []
print("🛒 E-COMMERCE ORDER PROCESSING")
print("=" * 60)
for cart_item in shopping_cart:
item_name = cart_item['item']
quantity = cart_item['quantity']
print(f"\nProcessing: {item_name} (x{quantity})")
# Check if item exists in inventory
inventory_item = None
for inv_item in inventory:
if inv_item['item'] == item_name:
inventory_item = inv_item
break # Found the item, stop searching
if not inventory_item:
print(f" ❌ Item '{item_name}' not found in inventory")
not_found_items.append(item_name)
continue # Skip to next cart item
# Check stock availability
if inventory_item['stock'] <= 0:
print(f" ⏭️ '{item_name}' is out of stock")
out_of_stock_items.append(item_name)
continue
if inventory_item['stock'] < quantity:
print(f" ⚠️ Only {inventory_item['stock']} available (you wanted {quantity})")
quantity = inventory_item['stock']
print(f" Adjusting quantity to {quantity}")
# Calculate cost
item_cost = inventory_item['price'] * quantity
# Check if customer has enough balance
if item_cost > customer_balance:
print(f" ❌ Insufficient balance! Need ₹{item_cost}, have ₹{customer_balance}")
print(f" Cannot complete this order.")
break # Stop processing entire order
# Process the order
customer_balance -= item_cost
inventory_item['stock'] -= quantity
order_total += item_cost
order_items.append(f"{item_name} x{quantity} = ₹{item_cost}")
print(f" ✅ Added: {item_name} x{quantity} = ₹{item_cost}")
print(f" Remaining balance: ₹{customer_balance}")
# Check if balance is getting low
if customer_balance < 1000:
print(f" ⚠️ Low balance warning: ₹{customer_balance} left")
else:
# This runs only if loop completed without break
print("\n" + "=" * 60)
print("✅ ORDER COMPLETED SUCCESSFULLY!")
print("All available items processed.")
print("\n" + "=" * 60)
print("📦 ORDER SUMMARY")
print("-" * 40)
if order_items:
for item in order_items:
print(f" {item}")
print("-" * 40)
print(f" TOTAL: ₹{order_total}")
print(f" Remaining balance: ₹{customer_balance}")
else:
print(" No items were processed.")
if out_of_stock_items:
print(f"\n⏭️ Out of stock items (skipped): {', '.join(out_of_stock_items)}")
if not_found_items:
print(f"\n❌ Items not found: {', '.join(not_found_items)}")
print("\n📊 INVENTORY STATUS")
print("-" * 40)
for item in inventory:
status = "✓" if item['stock'] > 0 else "✗"
print(f" {status} {item['item']}: {item['stock']} left")
# Control statements used:
# - break: stop searching inventory when item found
# - break: stop order if insufficient balance
# - continue: skip items not in inventory
# - continue: skip out of stock items
# - for-else: all items processed successfully
🔹 Example 4: Data Validation Pipeline
# User Registration Data Validation
user_data = [
{"username": "rahul123", "email": "rahul@email.com", "age": 25, "phone": "9876543210"},
{"username": "priya", "email": "invalid-email", "age": 30, "phone": "12345"}, # Invalid email & phone
{"username": "", "email": "amit@email.com", "age": 22, "phone": "9876543211"}, # Empty username
{"username": "neha_k", "email": "neha@email.com", "age": 17, "phone": "9876543212"}, # Underage
{"username": "raj_123", "email": "raj@email.com", "age": 35, "phone": "9876543213"},
{"username": "a"*50, "email": "long@email.com", "age": 28, "phone": "9876543214"} # Username too long
]
valid_users = []
invalid_count = 0
validation_errors = []
print("🔍 USER REGISTRATION VALIDATION PIPELINE")
print("=" * 60)
for user_num, user in enumerate(user_data, 1):
print(f"\n{'─'*50}")
print(f"Validating User {user_num}:")
errors = []
# Check if username is empty
if not user['username']:
errors.append("Username cannot be empty")
# Check username length
if len(user['username']) > 20:
errors.append(f"Username too long ({len(user['username'])} chars, max 20)")
# Check email format (simple check)
if '@' not in user['email'] or '.' not in user['email']:
errors.append("Invalid email format")
# Check age
if user['age'] < 18:
errors.append(f"Underage ({user['age']} < 18)")
# Check phone number length
if len(user['phone']) != 10 or not user['phone'].isdigit():
errors.append("Invalid phone number (need 10 digits)")
# If any errors, skip this user
if errors:
invalid_count += 1
validation_errors.append({
'user': user_num,
'username': user['username'] or "[EMPTY]",
'errors': errors
})
print(f"❌ Validation failed - skipping")
for error in errors:
print(f" • {error}")
continue # Skip to next user
# If we get here, user is valid
valid_users.append(user)
print(f"✅ User {user_num} is VALID")
print(f" Username: {user['username']}")
print(f" Email: {user['email']}")
print("\n" + "=" * 60)
print("📋 VALIDATION SUMMARY")
print("-" * 40)
print(f"Total users processed: {len(user_data)}")
print(f"✅ Valid users: {len(valid_users)}")
print(f"❌ Invalid users: {invalid_count}")
if validation_errors:
print("\n⚠️ Validation Errors:")
for error in validation_errors:
print(f"\n User {error['user']} ({error['username']}):")
for e in error['errors']:
print(f" • {e}")
# Check if any user has perfect data (all fields ideal)
ideal_user = None
for user in valid_users:
if user['age'] >= 25 and user['age'] <= 35 and '@gmail.com' in user['email']:
ideal_user = user
print(f"\n🏆 Found ideal user: {user['username']}")
break # Found one, stop searching
if ideal_user:
print("✅ Ideal user found - stopping search")
else:
print("\nℹ️ No ideal user found")
# Control statements used:
# - continue: skip invalid users, move to next
# - break: stop searching after finding ideal user
# - continue (implicit): normal loop flow
🔹 Control Statements Usage Summary
| Example | break Used |
continue Used |
Loop-else Used |
|---|---|---|---|
| ATM Machine | ✅ Correct PIN, emergency stop | ✅ Empty PIN, insufficient funds | ✅ All transactions processed |
| Student Grading | ❌ Not used | ✅ Invalid marks, failed students | ❌ Not used |
| Shopping Cart | ✅ Found item, insufficient balance | ✅ Out of stock, item not found | ✅ All items processed |
| Data Validation | ✅ Found ideal user | ✅ Invalid users | ❌ Not used |
| Password System | ✅ Correct password | ✅ Empty input | ✅ All attempts failed |
🎯 Key Takeaways from Real Examples
✏️ Design Challenge
🏦 ATM Withdrawal System
Design an ATM that:
- Allows 3 PIN attempts
- Skips withdrawal if amount > balance
- Shows receipt only if successful
📦 Order Processing
Process orders where:
- Skip out-of-stock items
- Stop if customer has no money
- Confirm if all items processed
📌 Quick Reference
🎉 Chapter Summary
✅ Real examples show how break, continue, and else work together
✅ break = emergency exit (correct PIN, found item, error)
✅ continue = skip problematic data (invalid, out of stock, empty)
✅ loop-else = "all done successfully" (no breaks occurred)
✅ Combine them for robust, efficient programs
✅ These patterns appear in every real application (ATMs, shopping, validation)
7.5 When & Why to Use These Statements
🔹 Making the Right Choice
Now that you understand break, continue, and pass, the key is knowing
which one to use and when. This section provides clear guidelines, decision trees,
and real-world scenarios to help you choose the right statement every time.
"Stop Now"
Exit the loop immediately
Use when you're done and don't need to continue
"Skip This"
Skip current iteration only
Use when current item is invalid but others might be valid
"Do Nothing"
Placeholder, does nothing
Use when syntax requires code but you're not ready
🔹 Detailed Comparison Table
| Statement | Purpose | When to Use | Analogy | Code Example |
|---|---|---|---|---|
| break | Stops loop immediately |
|
Finding keys in drawers – stop searching once found | if found: break |
| continue | Skips current iteration |
|
Quality check – reject defective item, check next | if invalid: continue |
| pass | Does nothing (placeholder) |
|
"Coming Soon" sign in empty store | def future(): pass |
🔹 Decision Tree – Which One to Use?
┌─────────────────────────────────┐
│ Start: What do you need? │
└─────────────────────────────────┘
│
┌─────────────┼─────────────┐
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Exit loop? │ │ Skip item? │ │ Placeholder?│
└─────────────┘ └─────────────┘ └─────────────┘
│ │ │
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ break │ │ continue │ │ pass │
│ "Stop now" │ │ "Skip this" │ │"Do nothing" │
└─────────────┘ └─────────────┘ └─────────────┘
│ │ │
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│• Found item │ │• Bad data │ │• Empty func │
│• Error │ │• Filter out │ │• Empty class│
│• User quit │ │• Skip cases │ │• TODO later │
│• Max tries │ │• Comments │ │• Exception │
└─────────────┘ └─────────────┘ └─────────────┘
- Ask: "Do I want to stop everything?" → Use
break - Ask: "Do I want to skip this one only?" → Use
continue - Ask: "Do I need a placeholder for later?" → Use
pass
🔹 When to Use break – Detailed Guide
-
🔍 Search Found – Stop when item located
for item in items: if item == target: print("Found!") break # Stop searching -
⚠️ Error Detected – Can't continue safely
for item in data: if not valid(item): print("Error in data") break # Stop processing -
🎮 Game Over – Player wants to quit
while playing: if user_quit: break # Exit game loop -
🔐 Login Success – Correct password entered
for attempt in range(3): if password == correct: print("Access granted") break # Don't try more attempts
-
Processing all items – Need to check everything
# DON'T: Need to validate ALL for item in data: if invalid(item): break # Stops early - bad! # Misses other items! -
Filtering data – Use continue instead
# DON'T: break stops everything for item in items: if unwanted(item): break # Wrong! Stops loop process(item) - Counting/accumulating – Need all values
🔹 When to Use continue – Detailed Guide
-
🧹 Data Cleaning – Skip invalid entries
for row in data: if row is None or row == "": continue # Skip empty rows process(row) -
🎯 Filtering – Process only wanted items
for num in numbers: if num % 2 != 0: continue # Skip odds print(f"Even: {num}") -
📝 File Processing – Skip comment lines
for line in file: if line.startswith('#'): continue # Skip comments process_data(line) -
🛒 Inventory – Skip out-of-stock
for item in cart: if item.stock == 0: continue # Can't buy add_to_order(item)
-
Search operations – Use break instead
# DON'T: continue keeps searching for item in items: if item == target: print("Found") continue # Wrong! Keeps going! # Wastes time on rest of items - Error that should stop – Break, don't continue
- Complex logic – Can make code hard to follow
🔹 When to Use pass – Detailed Guide
-
🏗️ Empty Function – Plan future features
def future_feature(): """TODO: Implement this later""" pass # Function body coming soon -
📦 Empty Class – Design class hierarchy
class Animal: """Base class for all animals""" pass # Will add methods later -
⚡ Exception Handling – Temporarily ignore
try: risky_operation() except Exception: pass # TODO: Add proper logging -
📝 Conditional Placeholders
if condition: pass # Handle this case later else: do_something()
-
Instead of continue – pass doesn't skip!
# DON'T: pass doesn't skip for num in numbers: if num % 2 == 0: pass # Does nothing! print(num) # Still prints evens! - Instead of break – pass won't exit loop
- In production without TODO – Confusing to others
- Silent exception handling – Always log errors!
🔹 Real-World Scenario Matching
| Scenario | What You Want | Best Statement | Why? |
|---|---|---|---|
| 🔍 Searching for a specific customer in database | Stop when found | break | No need to check remaining records |
| 📊 Processing sales data, skip negative values | Skip bad data, process rest | continue | Want to process valid data after skipping |
| 🏗️ Writing a class that will be expanded later | Empty placeholder | pass | Class needs body but not ready |
| 🎮 Game loop - player chooses to quit | Exit game completely | break | Stop the game loop entirely |
| 📝 Reading log file, ignore comment lines | Skip comments, process logs | continue | Want to see all log entries after skipping |
| 🔐 Login system - 3 attempts max | Stop after 3 failures | break | Account lock - no more attempts |
| 🛒 Shopping cart - out of stock items | Skip unavailable, process rest | continue | Still want to buy available items |
| 📦 API development - stub methods | Placeholder for future | pass | Methods will be implemented later |
⚠️ Common Misconceptions
"continue and pass are similar"
❌ WRONG! They are completely different:
continueskips to next iterationpassdoes nothing and continues normally
"break exits the program"
❌ WRONG! break only exits the current loop, not the whole program.
Code after the loop still runs.
"pass is just a comment"
❌ WRONG! pass is actual Python code that executes (doing nothing). Comments are ignored.
🔹 Best Practices Summary
break
- ✅ Use for search operations
- ✅ Use for error conditions
- ✅ Use for user exit
- ❌ Don't use when need all items
- ❌ Don't use for filtering
continue
- ✅ Use for data cleaning
- ✅ Use for filtering
- ✅ Use to skip special cases
- ❌ Don't use for search
- ❌ Don't use to exit loops
pass
- ✅ Use for placeholders
- ✅ Use for empty functions/classes
- ✅ Use with TODO comments
- ❌ Don't use instead of continue
- ❌ Don't use to ignore errors
📌 One-Liner Summary
🎉 Chapter Summary
✅ break = Emergency exit – use when you're done and want to stop completely
✅ continue = Skip one – use when current item is bad but others might be good
✅ pass = Placeholder – use when syntax requires code but you're not ready
✅ Decision Tree: Stop? → break | Skip? → continue | Placeholder? → pass
✅ Remember: break exits, continue skips one, pass does nothing
✅ Use the right tool for the right job – your code will be cleaner and more efficient!
🎓 Module 07 : Control Statements (Break, Continue, Pass) Successfully Completed
You have successfully completed this module of Python for Cybersecurity.
Keep building your expertise step by step — Learn Next Module →
🔄 Python Data Type Casting – Convert int, float & str Easily
Data type casting allows you to convert values from one type to another. Python supports implicit casting (automatic) and explicit casting (manual using functions).
8.1 Implicit Casting – Python Converts Automatically
🔹 What is Implicit Casting?
Implicit casting (also called automatic type conversion or type coercion) is when Python automatically converts one data type to another without you having to do anything. It's like having a smart assistant that knows how to handle different types of data!
When you perform operations with different data types, Python automatically converts the smaller type to the larger type to prevent data loss.
- You have ₹500 (rupees) and $10 (dollars)
- To add them, you need to convert one to the other
- Python automatically does this conversion for you!
# int + float → float
a = 5 # int
b = 3.2 # float
result = a + b
print(f"Result: {result}")
print(f"Type: {type(result)}")
# Output:
# Result: 8.2
# Type:
# What Python does behind the scenes:
# 1. Sees int (5) and float (3.2)
# 2. Converts int 5 → float 5.0
# 3. Adds 5.0 + 3.2 = 8.2
# 4. Result is float
✅ Python automatically promotes int to float to avoid losing decimal precision
Smaller → Larger (wider) types
# Boolean → Integer
print(True + 5) # 6 (True = 1)
# Integer → Float
print(10 + 3.7) # 13.7
# Integer → Complex
print(5 + 2j) # (5+2j)
# Float → Complex
print(3.5 + 2j) # (3.5+2j)
# Boolean → Float
print(False + 3.5) # 3.5 (False = 0)
🔹 More Implicit Casting Examples
# int + int → int
print(10 + 5) # 15 (int)
# int + float → float
print(10 + 3.14) # 13.14 (float)
# int + complex → complex
print(5 + 2j) # (5+2j)
# float + float → float
print(3.5 + 2.7) # 6.2 (float)
# float + complex → complex
print(3.5 + 2j) # (3.5+2j)
# bool + int → int
print(True + 10) # 11 (True = 1)
print(False + 10) # 10 (False = 0)
# bool + float → float
print(True + 3.5) # 4.5 (float)
# Subtraction
print(10 - 3.5) # 6.5 (float)
# Multiplication
print(5 * 2.5) # 12.5 (float)
# Division (always float!)
print(10 / 2) # 5.0 (float)
print(9 / 3) # 3.0 (float)
# Mixed operations
x = 10 # int
y = 3.5 # float
z = True # bool
result = x + y - z
print(result) # 12.5 (float)
# With complex numbers
c = 2 + 3j
print(5 + c) # (7+3j)
print(2.5 + c) # (4.5+3j)
🔹 Boolean in Implicit Casting
True = 1 and False = 0 when used in arithmetic!
print(True + 5) # 6
print(True * 10) # 10
print(True / 2) # 0.5
print(True ** 2) # 1
print(False + 5) # 5
print(False * 10) # 0
print(False / 2) # 0.0
print(False ** 2) # 0
print(True + False) # 1
print(True * False) # 0
print(10 + True - False) # 11
✅ When Implicit Casting Works
| Operation | Example | Result Type | Explanation |
|---|---|---|---|
| int + float | 5 + 3.2 |
float | int → float to preserve decimal |
| int + complex | 5 + 2j |
complex | int → complex (real part) |
| float + complex | 3.5 + 2j |
complex | float → complex (real part) |
| bool + int | True + 5 |
int | bool (True=1, False=0) → int |
| bool + float | True + 3.5 |
float | bool → float |
| int / int | 10 / 3 |
float | Division always returns float |
❌ When Implicit Casting Does NOT Work
# ❌ This will ERROR!
# "Hello" + 10
# TypeError: can only concatenate str to str
# ❌ This also errors
# "5" + 3
# TypeError
# ✅ You must cast explicitly
print("5" + str(3)) # "53"
print(int("5") + 3) # 8
# ❌ These will ERROR!
# [1,2,3] + 4
# TypeError: can only concatenate list to list
# ✅ Correct way
print([1,2,3] + [4]) # [1,2,3,4]
🔹 Visual Explanation
🎯 How Python Processes: 5 + 3.2
5 (int)
Detect float
5 → 5.0 (float)
5.0 + 3.2 = 8.2
🔹 Real-World Examples
# Calculating total price
price = 499 # int (₹)
tax = 49.99 # float
quantity = 3 # int
# Python automatically converts int to float
subtotal = price * quantity # 1497 (int)
total = subtotal + tax # 1546.99 (float)
print(f"Subtotal: ₹{subtotal}") # ₹1497
print(f"Total with tax: ₹{total}") # ₹1546.99
print(f"Type: {type(total)}") #
# Calculating mileage
distance = 350 # int (km)
fuel = 12.5 # float (liters)
# Division always returns float
mileage = distance / fuel
print(f"Mileage: {mileage} km/l")
print(f"Type: {type(mileage)}")
# Output:
# Mileage: 28.0 km/l
# Type:
# Student grades
scores = [85, 90, 78, 92] # all int
total = 0
for score in scores:
total += score # total remains int
average = total / len(scores) # division → float
print(f"Average: {average}") # 86.25 (float)
# Celsius to Fahrenheit
celsius = 37 # int
fahrenheit = (celsius * 9/5) + 32
print(f"{celsius}°C = {fahrenheit}°F")
print(f"Type: {type(fahrenheit)}")
# Output:
# 37°C = 98.6°F
# Type:
⚠️ Common Mistakes
- Assuming string + number works: Python doesn't auto-convert strings!
"5" + 3→ ERROR - Forgetting division always returns float:
10 / 2 = 5.0, not 5 - Expecting int rounding:
5 / 2 = 2.5, not 2 - Boolean confusion:
True + True = 2(True is 1) - Mixing incompatible types: List + int, string + float will ERROR
✏️ Quick Practice
1. What is 5 + 3.14? What type?
2. What is True + 10? What type?
3. What is 10 / 4? What type?
4. Will "5" + 3 work?
5. What is 5 + True + 2.5?
6. What is 10 / 3? What type?
📌 Quick Reference
🎉 Chapter Summary
✅ Implicit casting = Python automatically converts smaller types to larger types
✅ Hierarchy: bool → int → float → complex (smaller → larger)
✅ Division (/) always returns float even with two integers
✅ Boolean values: True = 1, False = 0 in arithmetic
✅ Strings + numbers: NOT automatically converted - must cast explicitly
✅ Prevents data loss by promoting to larger type
✅ Real-world use: Prices, averages, measurements, temperature conversions
8.2 Explicit Casting – Using int(), float(), str()
🔹 What is Explicit Casting?
Explicit casting (also called type conversion) is when you manually convert a value from one data type to another using special functions. Unlike implicit casting where Python does it automatically, here you're in control!
new_value = target_type(old_value)
# Examples:
x = int(3.14) # Convert float to int
y = float(10) # Convert int to float
z = str(100) # Convert int to string
⚠️ You must use the correct function for the target type you want!
- int() = Scissors – cuts off decimals
- float() = Measuring tape – adds precision
- str() = Label maker – turns anything into text
🔹 Complete Casting Functions Reference
| Function | Converts To | Valid Input Types | Example | Result | Notes |
|---|---|---|---|---|---|
| int() | Integer | float, string (digits), bool | int(3.9) |
3 | Truncates (removes decimal), doesn't round |
| int() | Integer | float, string (digits), bool | int("45") |
45 | String must contain only digits |
| int() | Integer | float, string (digits), bool | int(True) |
1 | True=1, False=0 |
| float() | Float | int, string (digits/decimal), bool | float(5) |
5.0 | Adds .0 to whole numbers |
| float() | Float | int, string (digits/decimal), bool | float("3.14") |
3.14 | String can have decimal point |
| float() | Float | int, string (digits/decimal), bool | float(False) |
0.0 | False=0.0, True=1.0 |
| str() | String | ANY type! | str(100) |
"100" | Most commonly used function |
| str() | String | ANY type! | str(3.14) |
"3.14" | Preserves decimal representation |
| str() | String | ANY type! | str([1,2,3]) |
"[1, 2, 3]" | Even converts lists! |
🔹 int() – Convert to Integer
# int() truncates (cuts off) decimals
print(int(3.14)) # 3
print(int(9.99)) # 9
print(int(-2.7)) # -2
print(int(5.0)) # 5
# ⚠️ int() does NOT round!
# 3.9 becomes 3, not 4
# For rounding, use round()
print(round(3.9)) # 4
# String must contain ONLY digits
print(int("123")) # 123
print(int(" 45 ")) # 45 (spaces ignored)
print(int("-50")) # -50 (negative OK)
# ❌ These will ERROR!
# int("3.14") # ValueError: invalid literal
# int("25A") # ValueError
# int("") # ValueError
# int("10.0") # ValueError (decimal not allowed)
# Boolean to int
print(int(True)) # 1
print(int(False)) # 0
# Useful for counting
count = 0
count += int(True) # count = 1
count += int(False) # count still 1
count += int(True) # count = 2
# int() can convert from different bases
# Binary (base 2)
print(int("1010", 2)) # 10
# Octal (base 8)
print(int("17", 8)) # 15
# Hexadecimal (base 16)
print(int("FF", 16)) # 255
# Useful for low-level programming!
🔹 float() – Convert to Float
# int → float adds .0
print(float(10)) # 10.0
print(float(-5)) # -5.0
print(float(0)) # 0.0
# Useful when you need decimal precision
result = float(10) / 3 # 3.3333333333333335
# String can have decimal point
print(float("3.14")) # 3.14
print(float("5")) # 5.0
print(float("-2.5")) # -2.5
print(float(" 1.5 ")) # 1.5 (spaces ignored)
# Scientific notation
print(float("1e3")) # 1000.0
print(float("2.5e-2")) # 0.025
# ❌ These will ERROR!
# float("12A") # ValueError
# float("") # ValueError
# Boolean to float
print(float(True)) # 1.0
print(float(False)) # 0.0
# Useful in calculations
score = float(True) * 100 # 100.0
# Float precision issues
print(float("0.1") + float("0.2"))
# 0.30000000000000004 (not exactly 0.3!)
# For exact decimal calculations
# Use decimal module
from decimal import Decimal
print(Decimal("0.1") + Decimal("0.2")) # 0.3
🔹 str() – Convert to String
# Integer to string
print(str(100)) # "100"
print(str(-50)) # "-50"
# Float to string
print(str(3.14)) # "3.14"
print(str(2.0)) # "2.0"
# Useful for string concatenation
age = 25
message = "I am " + str(age) + " years old"
print(message) # "I am 25 years old"
# Boolean to string
print(str(True)) # "True"
print(str(False)) # "False"
# Useful for messages
is_logged_in = True
status = "Login status: " + str(is_logged_in)
print(status) # "Login status: True"
# List to string
print(str([1, 2, 3])) # "[1, 2, 3]"
# Tuple to string
print(str((1, 2, 3))) # "(1, 2, 3)"
# Dictionary to string
print(str({"name": "Rahul"})) # "{'name': 'Rahul'}"
# Great for debugging!
data = [1, 2, 3]
print("Data: " + str(data))
# str() is for humans
# repr() is for Python
import datetime
today = datetime.datetime.now()
print(str(today)) # 2024-01-15 10:30:45
print(repr(today)) # datetime.datetime(2024, 1, 15, 10, 30, 45)
# str() is what you usually want
🔹 Real-World Applications
# User input always comes as string
age_str = input("Enter your age: ")
height_str = input("Enter your height (m): ")
# Convert to numbers for calculations
age = int(age_str)
height = float(height_str)
print(f"Next year you'll be {age + 1}")
print(f"Your height in cm: {height * 100}")
# Price calculations
prices = ["199.99", "49.50", "299.00"]
quantities = ["2", "1", "3"]
total = 0
for price, qty in zip(prices, quantities):
total += float(price) * int(qty)
print(f"Total: ₹{total}")
print("Receipt: ₹" + str(total))
# CSV data often comes as strings
csv_data = ["25,3.5,True", "30,4.2,False"]
for row in csv_data:
parts = row.split(",")
age = int(parts[0])
score = float(parts[1])
active = bool(parts[2]) # "True" becomes True
print(f"Age: {age}, Score: {score}, Active: {active}")
# Building reports with mixed types
sales = [1500, 2200, 1800]
total = sum(sales)
average = total / len(sales)
# Convert numbers to strings for report
report = "Sales Report\n"
report += "-" * 20 + "\n"
report += "Total: $" + str(total) + "\n"
report += "Average: $" + str(average) + "\n"
report += "Best: $" + str(max(sales))
print(report)
🔹 Common Casting Patterns
🔢 String → Number
num = int("123")
price = float("45.67")
📝 Number → String
text = str(123)
msg = "Total: " + str(45.67)
⚖️ Float → Integer
whole = int(3.14) # 3
⚠️ Common Mistakes
- int("3.14") – Error! String with decimal can't become int directly (use float() first)
- int("12A") – Error! String must contain ONLY digits
- float("") – Error! Empty string can't convert
- Forgetting str() in concatenation:
"Age: " + age→ Error! - Assuming int() rounds: int(3.9) = 3, not 4 (use round() for rounding)
- Converting without validation: Always validate user input before casting!
🔹 Safe Casting Techniques
def safe_int(value):
try:
return int(value)
except ValueError:
return None # or 0, or handle error
user_input = "123"
result = safe_int(user_input)
if result is not None:
print(f"Valid number: {result}")
# For integers
if user_input.isdigit():
num = int(user_input)
else:
print("Invalid number")
# For floats - need custom check
def is_float(s):
try:
float(s)
return True
except ValueError:
return False
✏️ Quick Practice
1. What is int(4.7)?
2. What is float(10)?
3. What is str(True)?
4. Will int("12.5") work?
5. Convert "3.14" to integer
6. Fix this: "Age: " + 25
📌 Quick Reference
🎉 Chapter Summary
✅ int() = convert to integer (truncates, doesn't round)
✅ float() = convert to float (adds .0 to whole numbers)
✅ str() = convert to string (works with ANY type)
✅ String to int: must contain only digits (no decimal)
✅ String to float: can have decimal point
✅ Always validate user input before casting
✅ Use try-except for safe casting
8.3 Casting Functions with Simple Examples
🔹 Understanding Casting Through Examples
The best way to understand casting is through simple, practical examples.
This section provides clear, real-world scenarios showing how int(), float(),
and str() work in everyday programming situations.
String → Number
Convert text to calculate
Number → Number
Change between numeric types
Number → String
Display numbers in text
🔹 Convert String → Number
# Simple integer string
num_str = "25"
num = int(num_str)
print(f"Original: {num_str} (type: {type(num_str)})")
print(f"Converted: {num} (type: {type(num)})")
print(f"Can do math: {num} + 5 = {num + 5}")
# Output:
# Original: 25 (type: )
# Converted: 25 (type: )
# Can do math: 25 + 5 = 30
# Decimal string
price_str = "19.99"
price = float(price_str)
print(f"Price string: {price_str}")
print(f"Price float: {price}")
print(f"With tax: ₹{price * 1.18:.2f}")
# String with spaces
height_str = " 5.8 "
height = float(height_str)
print(f"Height: {height} meters")
# Output:
# Price string: 19.99
# Price float: 19.99
# With tax: ₹23.59
# Without casting (ERROR!)
quantity_str = "5"
price_str = "10.50"
# total = quantity_str * price_str # TypeError!
# With casting (WORKS!)
quantity = int(quantity_str)
price = float(price_str)
total = quantity * price
print(f"Quantity: {quantity}")
print(f"Price: ₹{price}")
print(f"Total: ₹{total}")
# Multiple conversions
scores = ["85", "90", "78", "92"]
total_score = 0
for score in scores:
total_score += int(score)
average = total_score / len(scores)
print(f"Average score: {average}") # 86.25
# Convert various string formats
print(int("123")) # 123
print(int("-45")) # -45
print(int(" 67 ")) # 67 (spaces ignored)
print(float("3.14")) # 3.14
print(float("-2.5")) # -2.5
print(float(" 1.5e2 ")) # 150.0 (scientific)
# ❌ These will ERROR
# int("12.5") # ValueError: invalid literal
# float("12A") # ValueError
🔹 Convert Number → Number
# Integer to float
a = 10
b = float(a)
print(f"int: {a} (type: {type(a)})")
print(f"float: {b} (type: {type(b)})")
# Useful for precise division
result = a / 3 # 3.3333333333333335
result_float = b / 3 # 3.3333333333333335 (same)
# Practical example
total_items = 5
total_cost = 245.50
average = total_cost / float(total_items)
print(f"Average cost: ₹{average:.2f}") # ₹49.10
# Float to integer (TRUNCATES, doesn't round)
print(int(3.14)) # 3
print(int(9.99)) # 9
print(int(-2.7)) # -2
# Compare with round()
print(round(3.14)) # 3
print(round(3.9)) # 4
print(int(3.9)) # 3
# Practical: Remove decimal part
price = 199.99
dollars = int(price) # 199
cents = int((price - dollars) * 100) # 99
print(f"${dollars}.{cents:02d}") # $199.99
# Boolean to int
print(int(True)) # 1
print(int(False)) # 0
# Boolean to float
print(float(True)) # 1.0
print(float(False)) # 0.0
# Practical: Counting true values
responses = [True, False, True, True, False]
true_count = sum(int(r) for r in responses)
print(f"True count: {true_count}") # 3
# Conditional math
discount = 0.1 * int(is_member) # 0.1 if member, 0 if not
# Mixing different numeric types
quantity = 5 # int
price = 49.99 # float
tax_rate = 0.18 # float
subtotal = quantity * price # float
tax = float(quantity) * price * tax_rate # float
total = subtotal + tax
print(f"Subtotal: ₹{subtotal:.2f}")
print(f"Tax: ₹{tax:.2f}")
print(f"Total: ₹{total:.2f}")
# All work because Python handles mixed types!
🔹 Convert Number → String
# Integer to string
age = 25
age_str = str(age)
print(f"Age: {age_str} (type: {type(age_str)})")
# Essential for string concatenation
name = "Rahul"
message = name + " is " + str(age) + " years old"
print(message) # Rahul is 25 years old
# Without str() - ERROR!
# message = name + " is " + age + " years old" # TypeError!
# Float to string
price = 19.99
price_str = str(price)
print(f"Price: {price_str}")
# Formatting with string methods
print("₹" + str(price)) # ₹19.99
print("₹" + str(round(price, 1))) # ₹20.0
print("₹{:.2f}".format(price)) # ₹19.99 (better!)
# Scientific notation
large_num = 1e6
print(str(large_num)) # 1000000.0
# Boolean to string
is_active = True
status = str(is_active)
print(f"Status: {status}") # Status: True
# Useful for messages
is_member = False
message = "Member: " + str(is_member)
print(message) # Member: False
# In f-strings (no casting needed!)
print(f"Member: {is_member}") # Member: False
# Creating a simple report
sales = [1500, 2200, 1800, 2100]
total = sum(sales)
average = total / len(sales)
# Build report using str()
report = "SALES REPORT\n"
report += "=" * 30 + "\n"
for i, sale in enumerate(sales, 1):
report += "Day " + str(i) + ": $" + str(sale) + "\n"
report += "=" * 30 + "\n"
report += "Total: $" + str(total) + "\n"
report += "Average: $" + str(round(average, 2)) + "\n"
print(report)
🔹 Real-World Combined Examples
# Shopping cart with casting
cart_items = [
{"item": "Laptop", "price": "45000", "qty": "1"},
{"item": "Mouse", "price": "500", "qty": "2"},
{"item": "Keyboard", "price": "1500", "qty": "1"}
]
total = 0
receipt = "🛍️ YOUR RECEIPT\n"
receipt += "=" * 40 + "\n"
for item in cart_items:
price = float(item["price"])
qty = int(item["qty"])
subtotal = price * qty
total += subtotal
receipt += f"{item['item']:10} x{qty} ₹{price:7.2f} ₹{subtotal:8.2f}\n"
receipt += "=" * 40 + "\n"
receipt += f"{'TOTAL:':20} ₹{total:8.2f}\n"
print(receipt)
# User input always comes as strings
name = input("Enter name: ")
age_str = input("Enter age: ")
height_str = input("Enter height (m): ")
# Cast to appropriate types
age = int(age_str)
height = float(height_str)
# Calculate and display
years_to_100 = 100 - age
bmi_category = "Normal" if 18.5 <= height*height*22 else "Check"
# Build profile using str()
profile = "\n📋 USER PROFILE\n"
profile += "-" * 30 + "\n"
profile += "Name: " + name + "\n"
profile += "Age: " + str(age) + "\n"
profile += "Height: " + str(height) + "m\n"
profile += "Years to 100: " + str(years_to_100) + "\n"
print(profile)
# Student grades (as strings from input)
grade_strings = ["85", "90", "78", "92", "88"]
# Convert to integers for calculation
grades = [int(g) for g in grade_strings]
average = sum(grades) / len(grades)
# Determine letter grade
if average >= 90:
letter = "A"
elif average >= 80:
letter = "B"
else:
letter = "C"
# Display result (converting back to string)
result = "📝 GRADE REPORT\n"
result += "-" * 30 + "\n"
result += "Grades: " + ", ".join(grade_strings) + "\n"
result += "Average: " + str(round(average, 2)) + "\n"
result += "Letter Grade: " + letter + "\n"
print(result)
# Temperature conversion
celsius_str = "37"
celsius = float(celsius_str)
# Convert to Fahrenheit
fahrenheit = (celsius * 9/5) + 32
# Convert to Kelvin
kelvin = celsius + 273.15
# Display all formats
print("🌡️ TEMPERATURE CONVERSION")
print("-" * 30)
print("Celsius: " + str(celsius) + "°C")
print("Fahrenheit: " + str(round(fahrenheit, 2)) + "°F")
print("Kelvin: " + str(round(kelvin, 2)) + "K")
# Using f-strings (cleaner!)
print(f"\nCelsius: {celsius}°C")
print(f"Fahrenheit: {fahrenheit:.2f}°F")
🔹 With Casting vs Without Casting
# User input
age = input("Enter age: ")
# age is string: "25"
# ❌ This will ERROR!
# next_year = age + 1
# TypeError: can only concatenate str
# ❌ String comparison
if age > 18:
print("Adult") # Works but WRONG!
# Compares strings, not numbers!
# "5" > "18" is True! (alphabetical)
# ❌ String concatenation
price = 19.99
# message = "Price: $" + price
# TypeError!
# User input with casting
age = int(input("Enter age: "))
# age is int: 25
# ✅ Works correctly!
next_year = age + 1
print(f"Next year: {next_year}")
# ✅ Numeric comparison
if age > 18:
print("Adult") # Correct!
# ✅ String concatenation
price = 19.99
message = "Price: $" + str(price)
print(message) # Price: $19.99
🔹 Quick Casting Cheat Sheet
| From → To | Code | Example | Result |
|---|---|---|---|
| String → int | int("123") |
int("45") + 5 |
50 |
| String → float | float("3.14") |
float("2.5") * 2 |
5.0 |
| int → float | float(10) |
float(5) / 2 |
2.5 |
| float → int | int(3.14) |
int(9.9) + 1 |
10 |
| int → string | str(100) |
"Age: " + str(25) |
"Age: 25" |
| float → string | str(3.14) |
"Price: $" + str(19.99) |
"Price: $19.99" |
| bool → int | int(True) |
int(True) + int(False) |
1 |
| bool → string | str(True) |
"Status: " + str(True) |
"Status: True" |
⚠️ Common Mistakes
- int("12.5") – Error! String with decimal can't go directly to int
- float("12A") – Error! Non-digit characters not allowed
- "Age: " + 25 – Error! Must use str(25) or f-strings
- int(3.14) assumes rounding – It truncates, use round() for rounding
- Comparing strings vs numbers – "5" > "18" is True (alphabetical!)
✏️ Quick Practice
1. Convert "15" to int and add 5
2. Convert 7 to float and divide by 2
3. Create "Total: 100" from total=100
4. Fix: age = "25"; "Age: " + age
5. Convert "3.14" to int (two steps)
6. Calculate total: qty="3", price="4.99"
📌 Quick Reference
🎉 Chapter Summary
✅ String → int: int("123") (must be whole number)
✅ String → float: float("3.14") (decimals OK)
✅ int → float: float(5) → 5.0
✅ float → int: int(3.14) → 3 (truncates!)
✅ Number → string: str(100) → "100"
✅ bool → number: int(True) → 1
✅ Always cast user input before calculations!
8.4 String to Number Conversion – Complete Guide
🔹 What is String to Number Conversion?
Converting strings to numbers is one of the most common operations in programming, especially when dealing with user input, file data, or web forms. All external data comes as strings – you must convert them to numbers before performing calculations!
String Input
User input, files, APIs
Conversion
int() or float()
Number
For calculations
# String to integer (whole numbers only)
number = int(string_variable)
# String to float (decimal numbers allowed)
number = float(string_variable)
⚠️ The string must contain ONLY valid digits (and optional sign/decimal point)
✅ Valid String to Number Conversions
# Basic integer strings
print(int("100")) # 100
print(int("0")) # 0
print(int("-50")) # -50
print(int("+25")) # 25
# With whitespace (spaces ignored)
print(int(" 123 ")) # 123
print(int("\t45\n")) # 45 (tabs/newlines ignored)
# Leading zeros are fine
print(int("007")) # 7
# Large numbers
print(int("999999999")) # 999999999
# Different bases (advanced)
print(int("1010", 2)) # 10 (binary)
print(int("FF", 16)) # 255 (hexadecimal)
# Simple decimals
print(float("3.14")) # 3.14
print(float("-2.5")) # -2.5
print(float("+1.5")) # 1.5
# Integers become float
print(float("100")) # 100.0
print(float("-50")) # -50.0
# With whitespace
print(float(" 4.5 ")) # 4.5
print(float("\t6.7\n")) # 6.7
# Scientific notation
print(float("1e3")) # 1000.0
print(float("2.5e-2")) # 0.025
print(float("-1.2e4")) # -12000.0
# No decimal point needed
print(float("5")) # 5.0
❌ Invalid String to Number Conversions
# ❌ Letters in string
# int("Hello") # ValueError
# ❌ Decimal in string (for int)
# int("12.5") # ValueError
# ❌ Special characters
# int("$100") # ValueError
# int("25%") # ValueError
# ❌ Multiple signs
# int("+-10") # ValueError
# ❌ Empty string
# int("") # ValueError
# ❌ Spaces only
# int(" ") # ValueError
# ❌ Commas in numbers
# int("1,000") # ValueError
# ❌ Text after number
# int("25A") # ValueError
# int("12abc") # ValueError
# ❌ Letters in string
# float("Hello") # ValueError
# ❌ Multiple decimals
# float("3.14.15") # ValueError
# ❌ Special characters
# float("$3.14") # ValueError
# ❌ Empty string
# float("") # ValueError
# ❌ Spaces only
# float(" ") # ValueError
# ❌ Text after number
# float("12.5kg") # ValueError
# float("3.14abc") # ValueError
# ❌ Invalid scientific
# float("1e") # ValueError
# float("e5") # ValueError
🔹 Safe Conversion Techniques
def safe_int_convert(value):
"""Safely convert string to int"""
try:
return int(value)
except ValueError:
return None # or 0, or handle error
def safe_float_convert(value):
"""Safely convert string to float"""
try:
return float(value)
except ValueError:
return None
# Usage
user_input = input("Enter a number: ")
num = safe_int_convert(user_input)
if num is not None:
print(f"Valid number: {num}")
print(f"Double: {num * 2}")
else:
print("Invalid input! Please enter a number.")
# For integers - use isdigit()
def check_and_convert_int(value):
value = value.strip() # Remove whitespace
if value and (value.isdigit() or
(value[0] in '+-' and value[1:].isdigit())):
return int(value)
return None
# For floats - need custom validation
def is_float_string(s):
"""Check if string can be converted to float"""
s = s.strip()
if not s:
return False
# Count decimals (must be 0 or 1)
if s.count('.') > 1:
return False
# Check if rest is digits (with optional sign)
parts = s.split('.')
for part in parts:
if part and not (part.isdigit() or
(part[0] in '+-' and part[1:].isdigit())):
return False
return True
# Usage
value = "12.5"
if is_float_string(value):
num = float(value)
print(f"Valid float: {num}")
def get_valid_integer(prompt):
"""Keep asking until user enters a valid integer"""
while True:
try:
value = int(input(prompt))
return value
except ValueError:
print("❌ Invalid input! Please enter a whole number.")
def get_valid_float(prompt):
"""Keep asking until user enters a valid float"""
while True:
try:
value = float(input(prompt))
return value
except ValueError:
print("❌ Invalid input! Please enter a number.")
# Usage
age = get_valid_integer("Enter your age: ")
height = get_valid_float("Enter your height (m): ")
print(f"Age: {age}, Next year: {age + 1}")
print(f"Height: {height}m")
def clean_and_convert(value):
"""Remove common formatting and convert"""
# Remove currency symbols, commas, spaces
value = value.strip()
value = value.replace('$', '')
value = value.replace('₹', '')
value = value.replace(',', '')
value = value.replace('%', '')
try:
if '.' in value:
return float(value)
else:
return int(value)
except ValueError:
return None
# Examples
print(clean_and_convert("₹1,299")) # 1299
print(clean_and_convert("$49.99")) # 49.99
print(clean_and_convert("1,234")) # 1234
print(clean_and_convert("25%")) # 25
print(clean_and_convert("invalid")) # None
🔹 Real-World Applications
# Registration form with validation
def register_user():
print("📝 USER REGISTRATION")
print("-" * 30)
# Name (no conversion needed)
name = input("Name: ").strip()
# Age - must be integer
while True:
age_str = input("Age: ").strip()
try:
age = int(age_str)
if age < 0 or age > 150:
print("❌ Age must be between 0-150")
continue
break
except ValueError:
print("❌ Please enter a valid age (whole number)")
# Salary - can be float
while True:
salary_str = input("Monthly salary: ₹").strip()
try:
salary = float(salary_str)
if salary < 0:
print("❌ Salary cannot be negative")
continue
break
except ValueError:
print("❌ Please enter a valid salary")
# Display summary
print("\n✅ Registration successful!")
print(f"Name: {name}")
print(f"Age: {age}")
print(f"Salary: ₹{salary:,.2f}")
print(f"Annual: ₹{salary * 12:,.2f}")
# Run the registration
# register_user()
# Process CSV data (like from Excel)
csv_data = """Name,Age,Salary,Rating
Rahul,25,45000,4.5
Priya,30,52000,4.8
Amit,22,38000,3.9
Neha,28,49000,4.2"""
def process_csv(csv_text):
lines = csv_text.strip().split('\n')
headers = lines[0].split(',')
data = []
for line in lines[1:]:
values = line.split(',')
row = {}
for i, value in enumerate(values):
header = headers[i]
# Try to convert to appropriate type
if header in ['Age']:
try:
row[header] = int(value)
except ValueError:
row[header] = None
elif header in ['Salary', 'Rating']:
try:
row[header] = float(value)
except ValueError:
row[header] = None
else:
row[header] = value
data.append(row)
return data
# Process the data
employees = process_csv(csv_data)
# Calculate statistics
total_salary = 0
valid_ages = 0
for emp in employees:
if emp['Salary']:
total_salary += emp['Salary']
if emp['Age']:
valid_ages += 1
print(f"Average salary: ₹{total_salary/len(employees):,.2f}")
print(f"Valid age entries: {valid_ages}")
# Simple calculator with safe conversion
def calculator():
print("🧮 SIMPLE CALCULATOR")
print("=" * 30)
# Get first number
while True:
num1_str = input("Enter first number: ").strip()
try:
num1 = float(num1_str)
break
except ValueError:
print("❌ Invalid number! Try again.")
# Get operator
operators = ['+', '-', '*', '/']
while True:
op = input("Enter operator (+, -, *, /): ").strip()
if op in operators:
break
print("❌ Invalid operator!")
# Get second number
while True:
num2_str = input("Enter second number: ").strip()
try:
num2 = float(num2_str)
break
except ValueError:
print("❌ Invalid number! Try again.")
# Calculate
if op == '+':
result = num1 + num2
elif op == '-':
result = num1 - num2
elif op == '*':
result = num1 * num2
elif op == '/':
if num2 == 0:
print("❌ Cannot divide by zero!")
return
result = num1 / num2
# Display result
print(f"\n{num1} {op} {num2} = {result}")
# Run calculator
# calculator()
# Stock portfolio tracker
portfolio = [
{"symbol": "AAPL", "shares": "150", "price": "175.50"},
{"symbol": "GOOG", "shares": "25", "price": "2800.75"},
{"symbol": "TSLA", "shares": "10", "price": "650.25"},
{"symbol": "MSFT", "shares": "75", "price": "330.50"}
]
def calculate_portfolio_value(portfolio):
total = 0
holdings = []
for stock in portfolio:
try:
shares = int(stock["shares"])
price = float(stock["price"])
value = shares * price
holdings.append({
"symbol": stock["symbol"],
"shares": shares,
"price": price,
"value": value
})
total += value
except (ValueError, KeyError) as e:
print(f"❌ Error processing {stock.get('symbol', 'Unknown')}: {e}")
return holdings, total
# Calculate and display
holdings, total = calculate_portfolio_value(portfolio)
print("📊 PORTFOLIO SUMMARY")
print("=" * 50)
print(f"{'Symbol':<8} {'Shares':<8} {'Price':<10} {'Value':<12}")
print("-" * 50)
for h in holdings:
print(f"{h['symbol']:<8} {h['shares']:<8} ${h['price']:<10.2f} ${h['value']:<12.2f}")
print("=" * 50)
print(f"{'TOTAL':28} ${total:,.2f}")
🔹 String Validation Methods Comparison
| Method | For int | For float | Pros | Cons |
|---|---|---|---|---|
str.isdigit() |
✅ Works | ❌ No (can't handle decimal) | Simple, fast | No sign, no decimal |
try-except |
✅ Best | ✅ Best | Handles all cases, clean | Slightly slower |
| Regular Expressions | ✅ Works | ✅ Works | Very precise control | Complex to write |
| Custom validation | ✅ Possible | ✅ Possible | Full control | More code to maintain |
⚠️ Common String Conversion Mistakes
- Assuming int() can handle decimals –
int("12.5")causes ValueError! - Forgetting to handle empty strings –
int("")causes ValueError - Not stripping whitespace – User might enter " 123 " (spaces are OK, but always strip!)
- Ignoring locale formats – "1,000" has commas, need to clean first
- Not validating before conversion – Always use try-except for user input
- Assuming float() works for all decimals – "3.14.15" causes ValueError
- Forgetting about leading zeros – "007" converts fine to 7
- Not handling None values – int(None) causes TypeError
🔹 Best Practices for String to Number Conversion
1️⃣ Always validate user input
try:
num = int(input("Enter age: "))
except ValueError:
print("Invalid input!")
2️⃣ Strip whitespace first
user_input = input("Enter: ").strip()
if user_input:
num = float(user_input)
3️⃣ Use appropriate conversion function
# For whole numbers
age = int(age_str)
# For decimals
price = float(price_str)
4️⃣ Clean formatted numbers
def clean_number(s):
return s.replace(',', '').replace('$', '')
✏️ Quick Practice
1. Convert "123" to int
2. Convert "45.67" to float
3. What happens with int("12.5")?
4. Safely convert user input
5. Clean and convert "$1,299"
6. Handle " 45 "
📌 Quick Reference
🎉 Chapter Summary
✅ int(string) → converts to integer (no decimals allowed)
✅ float(string) → converts to float (decimals OK)
✅ Always validate with try-except for user input
✅ Strip whitespace with .strip() before converting
✅ Clean formatted numbers (remove $ , % etc.)
✅ Common errors: int("12.5"), int(""), int("12A")
✅ Best practice: Use float() for all numbers, then convert to int if needed
8.5 Common Casting Mistakes Beginners Make
🔹 Why Casting Mistakes Happen
Casting mistakes are among the most common errors beginners face in Python. Understanding these pitfalls will save you hours of debugging and help you write robust, error-free code. Let's explore the most frequent mistakes and how to avoid them!
String to Number Errors
Most common casting mistake
String Concatenation
Forgetting str()
Rounding Confusion
int() vs round()
Other Issues
Implicit casting confusion
Mistake #1: Converting Non-Numeric Strings
# ❌ These will ALL crash!
user_input = "Hello"
# num = int(user_input) # ValueError!
price = "25 dollars"
# value = float(price) # ValueError!
quantity = "12 items"
# count = int(quantity) # ValueError!
age = "twenty"
# years = int(age) # ValueError!
# The error message:
# ValueError: invalid literal for int() with base 10: 'Hello'
# ✅ Always validate first!
user_input = "Hello"
try:
num = int(user_input)
print(f"Converted: {num}")
except ValueError:
print("❌ Invalid number format")
# Better: Check before converting
def safe_int_convert(value):
"""Safely convert to int, return None if invalid"""
try:
return int(value.strip())
except ValueError:
return None
# Extract numbers from strings
import re
text = "25 dollars"
numbers = re.findall(r'\d+', text)
if numbers:
value = int(numbers[0])
print(f"Extracted: {value}") # 25
Mistake #2: Forgetting str() in String Concatenation
# ❌ These will ALL crash!
name = "Rahul"
age = 25
# Trying to concatenate string and int
# message = "My name is " + name + " and I am " + age + " years old"
# TypeError: can only concatenate str (not "int") to str
# Common mistakes in print statements
# print("Age: " + age) # TypeError!
# Building strings for display
# result = "Total: " + total # TypeError!
# Creating error messages
# error_msg = "Error code: " + 404 # TypeError!
# ✅ Always convert numbers to strings
name = "Rahul"
age = 25
# Method 1: Using str()
message = "My name is " + name + " and I am " + str(age) + " years old"
print(message)
# Method 2: Using f-strings (BEST!)
message = f"My name is {name} and I am {age} years old"
print(message)
# Method 3: Using .format()
message = "My name is {} and I am {} years old".format(name, age)
print(message)
# Method 4: Using print with multiple arguments
print("My name is", name, "and I am", age, "years old")
# For building strings
total = 450.50
result = "Total: ₹" + str(total) # Total: ₹450.5
result_f = f"Total: ₹{total:.2f}" # Total: ₹450.50 (better!)
name = "Rahul"
age = 25
score = 85.5
print(f"Name: {name}, Age: {age}, Score: {score}")
# Output: Name: Rahul, Age: 25, Score: 85.5
Mistake #3: Assuming int() Rounds Numbers
# Many beginners think int() rounds
value = 3.9
result = int(value)
print(f"int(3.9) = {result}") # 3 (not 4!)
value = 3.1
result = int(value)
print(f"int(3.1) = {result}") # 3 (not 3!)
value = -2.7
result = int(value)
print(f"int(-2.7) = {result}") # -2 (towards zero)
# This causes bugs in:
# - Grade calculations
# - Financial calculations
# - Statistical analysis
# - User expectations
# int() TRUNCATES (removes decimal, doesn't round)
print(f"int(3.9) = {int(3.9)}") # 3
print(f"int(3.1) = {int(3.1)}") # 3
print(f"int(-2.7) = {int(-2.7)}") # -2 (towards zero)
# round() ROUNDS to nearest integer
print(f"round(3.9) = {round(3.9)}") # 4
print(f"round(3.1) = {round(3.1)}") # 3
print(f"round(-2.7) = {round(-2.7)}") # -3
# For specific decimal places
price = 19.995
print(f"Rounded to 2 decimals: {round(price, 2)}") # 20.0
# math.floor() and math.ceil()
import math
print(f"floor(3.9) = {math.floor(3.9)}") # 3 (always down)
print(f"ceil(3.1) = {math.ceil(3.1)}") # 4 (always up)
| Function | 3.9 | 3.1 | -2.7 | Behavior |
|---|---|---|---|---|
int() |
3 | 3 | -2 | Truncates (removes decimal, toward zero) |
round() |
4 | 3 | -3 | Rounds to nearest integer |
math.floor() |
3 | 3 | -3 | Rounds down (toward negative infinity) |
math.ceil() |
4 | 4 | -2 | Rounds up (toward positive infinity) |
Mistake #4: Casting Without Validation
# ❌ Dangerous! Assumes input is valid
age = int(input("Enter age: ")) # Crashes if user types "twenty"
height = float(input("Enter height: ")) # Crashes if input is invalid
# No error handling
price = float("$19.99") # ValueError!
# No whitespace handling
user_input = " 45 "
value = int(user_input) # Works, but better to strip
# No empty check
data = input("Enter data: ")
if data: # What if data is "abc"?
num = int(data) # Still crashes!
# ✅ Always validate user input
def get_valid_int(prompt):
"""Get a valid integer from user"""
while True:
try:
value = int(input(prompt).strip())
return value
except ValueError:
print("❌ Please enter a valid whole number")
def get_valid_float(prompt):
"""Get a valid float from user"""
while True:
try:
value = float(input(prompt).strip())
return value
except ValueError:
print("❌ Please enter a valid number")
# Clean and validate
def safe_convert(value, target_type):
"""Safely convert to target type"""
try:
value = value.strip()
if target_type == int:
return int(value)
elif target_type == float:
return float(value)
else:
return None
except ValueError:
return None
# Usage
age = get_valid_int("Enter age: ")
height = get_valid_float("Enter height: ")
Mistake #5: Confusing Implicit vs Explicit Casting
# ❌ Assuming Python will convert anything
# result = "5" + 3 # Error! (can't convert implicitly)
# Thinking all operations auto-convert
# total = "10" * "2" # Error!
# Assuming int + float = int
x = 5 + 3.5
print(f"5 + 3.5 = {x}") # 8.5 (float, not int!)
# Thinking division returns int
result = 10 / 2
print(f"10 / 2 = {result}") # 5.0 (float, not 5!)
# Expecting string to number auto-conversion
# if "5" > 3: # TypeError!
# ✅ Implicit casting rules:
# Numeric types only (bool, int, float, complex)
print(5 + 3.5) # 8.5 (float)
print(True + 5) # 6 (True=1)
print(10 / 2) # 5.0 (division always float)
# ✅ Explicit casting needed for:
# String to number: int("5") or float("5")
# Number to string: str(5)
# String to string: no casting needed
# ✅ What works:
print("5" + str(3)) # "53" (explicit)
print(int("5") + 3) # 8 (explicit)
print(5 + 3) # 8 (both int)
print(5.0 + 3) # 8.0 (implicit)
# ✅ Using f-strings avoids confusion
value = 42
print(f"The value is {value}") # No casting needed!
🔹 Additional Common Mistakes
# ❌ Empty string causes ValueError
# num = int("") # ValueError
# ✅ Check for empty first
value = ""
if value.strip():
num = int(value)
else:
print("Empty input")
# ❌ Works but not clean
value = " 123 "
num = int(value) # Works, but risky
# ✅ Always strip first
value = " 123 ".strip()
num = int(value) # Clean!
# ❌ None causes TypeError
value = None
# num = int(value) # TypeError!
# ✅ Check for None first
if value is not None:
num = int(value)
else:
print("Value is None")
# ❌ "1,000" has comma
# num = int("1,000") # ValueError!
# ✅ Clean first
value = "1,000".replace(",", "")
num = int(value) # 1000
# For currency
price = "$19.99".replace("$", "")
num = float(price) # 19.99
🔹 Common Error Messages & What They Mean
| Error Message | Cause | Example | Solution |
|---|---|---|---|
ValueError: invalid literal for int() |
String contains non-digit characters | int("12A") |
Validate with try-except |
TypeError: can only concatenate str |
Mixing string and number with + | "Age: " + 25 |
Use str() or f-strings |
ValueError: could not convert string to float |
Invalid float format | float("3.14.15") |
Check format before converting |
TypeError: int() argument must be a string |
Passing None or wrong type | int(None) |
Check for None first |
ValueError: empty string for int() |
Empty string passed to int() | int("") |
Check if string is empty |
🔹 Casting Mistakes Prevention Checklist
❌ DON'T
- Assume user input is valid
- Use + to mix strings and numbers
- Think int() rounds numbers
- Convert without checking for None
- Ignore whitespace in strings
- Forget about locale formatting
- Assume division returns int
✅ DO
- Use try-except for conversions
- Use f-strings for string formatting
- Use round() when you need rounding
- Check for None before converting
- Always .strip() user input
- Clean formatted strings first
- Remember division always returns float
📌 Casting Mistakes Quick Reference
int("12.5") → Error!
float("12.5") → 12.5
int(float("12.5")) → 12
"Age: " + 25 → Error!
f"Age: {25}" → Works!
int(3.9) = 3 (not 4!)
✏️ Identify the Mistake
1. int("3.14") - What's wrong?
2. "Score: " + 95 - What's wrong?
3. int(7.9) expecting 8 - What's wrong?
4. int(user_input) without validation
5. int("") - What's wrong?
6. int("1,000") - What's wrong?
🎉 Chapter Summary
✅ int() truncates (removes decimals) - does NOT round
✅ str() is required when joining numbers with text (or use f-strings)
✅ Always validate user input with try-except
✅ Clean strings first: .strip(), .replace(",", ""), .replace("$", "")
✅ int("12.5") fails - use float() then int()
✅ Division (/) always returns float, not int
✅ f-strings are your best friend for mixing text and numbers!
🎓 Module 08 : Data Type Casting (int, float, str) Successfully Completed
You have successfully completed this module of Python for Cybersecurity.
Keep building your expertise step by step — Learn Next Module →
🔢 Python Numbers – int, float & complex Explained Simply
Python supports three main numeric types: int (whole numbers), float (decimal numbers), and complex (real + imaginary). Numbers play a major role in calculations, data processing, and scientific computing.
9.1 Integer – Whole Numbers
🔹 What are Integers?
Integers (int) are whole numbers without any decimal points – no fractions, no fractional parts. They can be positive, negative, or zero. Think of them as the numbers you use for counting: 1 apple, 5 books, -3 degrees, 0 balance.
Positive
10, 25, 1000, 9999
Negative
-5, -100, -999, -1
Zero
0 (neutral)
# Different ways to create integers
a = 10 # Positive integer
b = -5 # Negative integer
c = 0 # Zero
d = 1_000_000 # Underscores for readability (Python 3.6+)
e = +42 # Explicit positive sign (optional)
print(f"a = {a}, type: {type(a)}")
print(f"b = {b}, type: {type(b)}")
print(f"c = {c}, type: {type(c)}")
print(f"d = {d}, type: {type(d)}") # 1000000
print(f"e = {e}, type: {type(e)}")
⚠️ Note: Underscores in numbers (1_000_000) are ignored by Python - they just make large numbers readable!
🔹 Python's Unlimited Integer Size
# Python handles arbitrarily large integers
small = 1
large = 999999999999999999999999999999
huge = 10 ** 100 # 1 followed by 100 zeros
massive = 2 ** 1000 # 2 to the power 1000
print(f"Large number: {large}")
print(f"Huge number has {len(str(huge))} digits")
print(f"Massive number has {len(str(massive))} digits")
# In C/Java, these would overflow!
# In Python, they work perfectly
# Calculate with huge numbers
result = huge * massive
print(f"Result has {len(str(result))} digits")
# Factorial of 100 - huge number!
import math
fact50 = math.factorial(50)
fact100 = math.factorial(100)
print(f"50! has {len(str(fact50))} digits")
print(f"100! has {len(str(fact100))} digits")
# First few digits of 100!
print(f"100! = {str(fact100)[:50]}...")
# This would overflow in most languages!
# Python handles it effortlessly
🔹 Integer Operations
a = 15
b = 4
# Addition
print(f"{a} + {b} = {a + b}") # 19
# Subtraction
print(f"{a} - {b} = {a - b}") # 11
# Multiplication
print(f"{a} * {b} = {a * b}") # 60
# Division (always returns float!)
print(f"{a} / {b} = {a / b}") # 3.75
# Floor division (integer division)
print(f"{a} // {b} = {a // b}") # 3
# Modulus (remainder)
print(f"{a} % {b} = {a % b}") # 3
# Exponentiation
print(f"{a} ** 2 = {a ** 2}") # 225
# Bitwise operations
x = 5 # binary: 0101
y = 3 # binary: 0011
print(f"x & y (AND) = {x & y}") # 1 (0001)
print(f"x | y (OR) = {x | y}") # 7 (0111)
print(f"x ^ y (XOR) = {x ^ y}") # 6 (0110)
print(f"~x (NOT) = {~x}") # -6
print(f"x << 1 (left shift) = {x << 1}") # 10 (1010)
print(f"x >> 1 (right shift) = {x >> 1}") # 2 (0010)
# Check if even/odd
def is_even(n):
return n % 2 == 0
print(f"10 is even: {is_even(10)}")
print(f"7 is even: {is_even(7)}")
🔹 Integers in Different Number Bases
# Prefix: 0b
a = 0b1010 # 10 in decimal
b = 0b1111 # 15 in decimal
print(f"0b1010 = {a}")
print(f"0b1111 = {b}")
# Convert to binary
print(f"bin(10) = {bin(10)}")
print(f"bin(255) = {bin(255)}")
# Prefix: 0o
a = 0o12 # 10 in decimal
b = 0o17 # 15 in decimal
print(f"0o12 = {a}")
print(f"0o17 = {b}")
# Convert to octal
print(f"oct(10) = {oct(10)}")
print(f"oct(64) = {oct(64)}")
# Prefix: 0x
a = 0xA # 10 in decimal
b = 0xFF # 255 in decimal
print(f"0xA = {a}")
print(f"0xFF = {b}")
# Convert to hex
print(f"hex(10) = {hex(10)}")
print(f"hex(255) = {hex(255)}")
# Convert from any base to decimal
print(int("1010", 2)) # 10 (binary)
print(int("12", 8)) # 10 (octal)
print(int("A", 16)) # 10 (hex)
# Custom base conversion
print(int("101", 2)) # 5
print(int("101", 3)) # 10 (1×3² + 0×3¹ + 1×3⁰)
🔹 Integer Methods and Useful Functions
# bit_length() - number of bits needed
x = 255
print(f"bit_length of {x}: {x.bit_length()}") # 8 (11111111)
x = 1024
print(f"bit_length of {x}: {x.bit_length()}") # 11
# to_bytes() and from_bytes()
x = 1024
bytes_repr = x.to_bytes(2, byteorder='big')
print(f"bytes: {bytes_repr}")
# Check if integer is integer (always True for int)
print(f"(10).is_integer(): {(10).is_integer()}") # True
# Note: This method actually belongs to float, not int!
# abs() - absolute value
print(f"abs(-10) = {abs(-10)}") # 10
print(f"abs(5) = {abs(5)}") # 5
# pow() - power
print(f"pow(2, 8) = {pow(2, 8)}") # 256
print(f"pow(3, 3) = {pow(3, 3)}") # 27
# divmod() - quotient and remainder
q, r = divmod(17, 5)
print(f"17 ÷ 5 = {q} remainder {r}") # 3 remainder 2
# Conversion functions
print(f"int(3.14) = {int(3.14)}") # 3
print(f"int('123') = {int('123')}") # 123
print(f"int(True) = {int(True)}") # 1
print(f"int(False) = {int(False)}") # 0
✔ Why Integers are Useful
📌 Counting
Students, items, loops, iterations
count = 0
for i in range(10):
count += 1
📌 Indexing
List positions, array indices
fruits[0] # First item
fruits[-1] # Last item
📌 No Size Limit
Python handles huge numbers
big = 10**100
# No overflow error!
📌 Whole Number Calculations
Perfect for exact arithmetic
5 + 3 = 8 (exact)
10 // 3 = 3 (floor)
📌 Memory Efficient
Small integers use less memory
# More efficient than float
# for whole numbers
📌 Multiple Representations
Binary, octal, hex available
bin(10) # '0b1010'
hex(255) # '0xff'
🔹 Real-World Applications
# Product quantity and pricing
class ShoppingCart:
def __init__(self):
self.items = {}
def add_item(self, item, quantity):
if quantity <= 0:
raise ValueError("Quantity must be positive")
self.items[item] = self.items.get(item, 0) + quantity
def remove_item(self, item, quantity):
if item in self.items:
self.items[item] -= quantity
if self.items[item] <= 0:
del self.items[item]
def get_total_items(self):
return sum(self.items.values())
# Usage
cart = ShoppingCart()
cart.add_item("Laptop", 2)
cart.add_item("Mouse", 5)
print(f"Total items: {cart.get_total_items()}") # 7
# Player stats and scores
class Player:
def __init__(self, name):
self.name = name
self.score = 0
self.level = 1
self.lives = 3
self.xp = 0
def add_score(self, points):
self.score += points
self.xp += points
# Level up every 100 XP
self.level = (self.xp // 100) + 1
def lose_life(self):
self.lives -= 1
return self.lives > 0
player = Player("Hero")
player.add_score(150)
print(f"Level: {player.level}, XP: {player.xp}") # Level: 2, XP: 150
# Statistical calculations
data = [45, 67, 23, 89, 12, 56, 78, 34]
# Using integers for calculations
total = sum(data)
count = len(data)
mean = total / count # Becomes float
# Mode calculation (most frequent)
from collections import Counter
freq = Counter(data)
mode = max(freq.items(), key=lambda x: x[1])
print(f"Total: {total} (int)")
print(f"Count: {count} (int)")
print(f"Mean: {mean:.2f} (float)")
print(f"Mode: {mode[0]} appears {mode[1]} times")
# Time calculations using integers
import time
# Unix timestamp (seconds since 1970)
timestamp = int(time.time())
print(f"Current timestamp: {timestamp}")
# Convert seconds to hours, minutes, seconds
def format_time(seconds):
hours = seconds // 3600
minutes = (seconds % 3600) // 60
secs = seconds % 60
return f"{hours}h {minutes}m {secs}s"
duration = 3665 # seconds
print(format_time(duration)) # 1h 1m 5s
⚠️ Common Mistakes with Integers
- Division returns float:
5 / 2 = 2.5, not 2! Use//for integer division - int("12.5") – Error! String with decimal can't convert directly to int
- Forgetting about integer overflow: Not an issue in Python, but in other languages it is!
- Assuming int() rounds:
int(3.9) = 3(truncates, doesn't round) - Mixing int and None:
int(None)causes TypeError - Large int performance: Very large integers (> 2^63) are slower than small ones
🔹 Python int vs Other Languages
| Language | Integer Type | Size Limit | Example |
|---|---|---|---|
| Python | int | Unlimited (memory bound) | 10**1000 works! |
| C/C++ | int | Usually 32-bit (max 2.1 billion) | 2147483647 + 1 overflows |
| Java | int | 32-bit (max 2.1 billion) | Integer.MAX_VALUE + 1 wraps |
| Java | long | 64-bit (max 9.2 × 10¹⁸) | Still limited! |
| JavaScript | Number | 53-bit integer precision | 2**53 + 1 loses precision |
✏️ Quick Practice
1. What is 17 // 5?
2. Convert binary 1010 to decimal
3. What is 2 ** 100?
4. What is int(7.9)?
5. How to write 1 million with underscores?
6. What's 0xFF in decimal?
📌 Quick Reference
🎉 Chapter Summary
✅ int = whole numbers (positive, negative, zero)
✅ No size limit – Python handles arbitrarily large integers
✅ Operations: +, -, *, / (float), // (floor), % (mod), ** (power)
✅ Multiple bases: binary (0b), octal (0o), hex (0x)
✅ int() truncates decimal part – does NOT round
✅ Use underscores for readability: 1_000_000
✅ Perfect for counting, indexing, loops, and exact arithmetic
9.2 Float – Decimal Numbers
🔹 What are Floats?
A float (floating-point number) represents numbers with decimal points. They're essential when you need precision – prices, measurements, scientific values, and anywhere fractions or decimals appear in real life.
💰 Financial
Prices: ₹199.99, ₹49.50
🌡️ Scientific
Temp: 36.6°C, 98.6°F
⚖️ Measurements
Weight: 75.5 kg, 5.8 ft
# Different ways to create floats
x = 10.5 # Standard decimal
y = -3.14 # Negative float
z = 0.0 # Zero as float
w = .5 # Shorthand for 0.5
v = 2. # Shorthand for 2.0
a = 1.5e3 # Scientific notation: 1.5 × 10³ = 1500.0
b = 2.5e-2 # Scientific notation: 2.5 × 10⁻² = 0.025
print(f"x = {x}, type: {type(x)}")
print(f"y = {y}, type: {type(y)}")
print(f"z = {z}, type: {type(z)}")
print(f"w = {w}, type: {type(w)}")
print(f"v = {v}, type: {type(v)}")
print(f"a = {a}, type: {type(a)}")
print(f"b = {b}, type: {type(b)}")
⚠️ Scientific notation is great for very large or very small numbers!
🔹 Float Operations
a = 10.5
b = 3.2
# Addition
print(f"{a} + {b} = {a + b}") # 13.7
# Subtraction
print(f"{a} - {b} = {a - b}") # 7.3
# Multiplication
print(f"{a} * {b} = {a * b}") # 33.6
# Division
print(f"{a} / {b} = {a / b}") # 3.28125
# Floor division (with floats)
print(f"{a} // {b} = {a // b}") # 3.0
# Modulus (remainder)
print(f"{a} % {b} = {a % b}") # 0.8999999999999986
# Exponentiation
print(f"{a} ** 2 = {a ** 2}") # 110.25
# Python automatically converts int to float
int_num = 5
float_num = 2.5
result1 = int_num + float_num
result2 = int_num * float_num
result3 = int_num / float_num
print(f"int {int_num} + float {float_num} = {result1}")
print(f"Type: {type(result1)}") # float
print(f"int {int_num} * float {float_num} = {result2}")
print(f"Type: {type(result2)}") # float
print(f"int {int_num} / float {float_num} = {result3}")
print(f"Type: {type(result3)}") # float
# Division always returns float
print(f"10 / 2 = {10 / 2}") # 5.0, not 5!
print(f"Type: {type(10 / 2)}") # float
🔹 Float Precision Issues
# This is NOT a bug - it's how floats work!
print(0.1 + 0.2) # 0.30000000000000004 (not 0.3!)
# Comparison fails!
print(0.1 + 0.2 == 0.3) # False!
# More examples
print(0.1 * 3) # 0.30000000000000004
print(1.2 - 1.0) # 0.19999999999999996
print(0.3 / 0.1) # 2.9999999999999996
# Why? Binary can't represent some decimals exactly
# Just like 1/3 = 0.333333... in decimal
# 1. Use round() for comparison
a = 0.1 + 0.2
b = 0.3
print(round(a, 10) == round(b, 10)) # True
# 2. Use math.isclose() for comparison
import math
print(math.isclose(0.1 + 0.2, 0.3)) # True
# 3. Use Decimal for exact calculations
from decimal import Decimal
d1 = Decimal('0.1')
d2 = Decimal('0.2')
print(d1 + d2) # 0.3 exactly!
# 4. Format for display
price = 0.1 + 0.2
print(f"Price: ${price:.2f}") # $0.30
🔹 Converting to/from Float
# From integer
print(float(10)) # 10.0
print(float(-5)) # -5.0
# From string
print(float("3.14")) # 3.14
print(float("7")) # 7.0
print(float(" -2.5 ")) # -2.5 (spaces ignored)
# Scientific notation
print(float("1.5e3")) # 1500.0
print(float("2e-2")) # 0.02
# From boolean
print(float(True)) # 1.0
print(float(False)) # 0.0
# ❌ These will error
# float("12A") # ValueError
# float("") # ValueError
# Float to int (truncates!)
print(int(3.14)) # 3
print(int(3.9)) # 3 (not 4!)
print(int(-2.7)) # -2
# Float to string
print(str(3.14)) # "3.14"
print(str(2.0)) # "2.0"
# Rounding instead of truncating
print(round(3.14)) # 3
print(round(3.9)) # 4
print(round(-2.7)) # -3
# Round to specific decimals
print(round(3.14159, 2)) # 3.14
print(round(3.14159, 3)) # 3.142
🔹 Float Methods and Functions
# is_integer() - check if float represents an integer
print((3.0).is_integer()) # True
print((3.14).is_integer()) # False
# as_integer_ratio() - get exact fraction
x = 3.75
ratio = x.as_integer_ratio()
print(f"{x} = {ratio[0]}/{ratio[1]}") # 15/4
# hex() - hexadecimal representation
print((3.14).hex()) # 0x1.91eb851eb851fp+1
# abs() - absolute value
print(abs(-3.14)) # 3.14
# round() - rounding
print(round(3.14159, 2)) # 3.14
# pow() - power (returns float)
print(pow(2.5, 3)) # 15.625
# divmod() with floats
q, r = divmod(10.5, 3.2)
print(f"quotient: {q}, remainder: {r}") # 3.0, 0.9
# Formatting floats
price = 49.995
print(f"{price:.2f}") # "50.00"
print(f"{price:.1f}") # "50.0"
print(f"{price:.0f}") # "50"
🔹 Special Float Values
import math
inf = float('inf')
print(inf) # inf
print(inf > 999999) # True
# Negative infinity
ninf = float('-inf')
print(ninf) # -inf
# Check for infinity
print(math.isinf(inf)) # True
nan = float('nan')
print(nan) # nan
# NaN is not equal to itself!
print(nan == nan) # False!
# Check for NaN
import math
print(math.isnan(nan)) # True
# Division by zero
# 1.0 / 0.0 # ZeroDivisionError
# But float division with inf
print(1.0 / 1e-1000) # inf
# Invalid operations
import math
print(math.sqrt(-1.0)) # ValueError
✔ Why Float is Used
💰 Billing
Price calculations, taxes, discounts
price = 199.99
qty = 3
total = price * qty
🔬 Scientific
Measurements, constants, formulas
g = 9.81 # gravity
pi = 3.14159
area = pi * r ** 2
📊 Statistics
Averages, percentages, ratios
average = sum/len
percentage = (score/total)*100
🌡️ Temperature
Weather, body temperature
temp = 36.6 # Celsius
fever = temp > 37.5
📏 Measurements
Height, weight, distance
height = 5.8 # feet
weight = 72.5 # kg
📈 Percentages
Discounts, interest rates
discount = 0.15
final = price * (1 - discount)
🔹 Real-World Applications
class BankAccount:
def __init__(self, balance=0.0):
self.balance = balance
def deposit(self, amount):
if amount <= 0:
raise ValueError("Amount must be positive")
self.balance += amount
return self.balance
def withdraw(self, amount):
if amount > self.balance:
raise ValueError("Insufficient funds")
self.balance -= amount
return self.balance
def add_interest(self, rate):
"""Add annual interest rate (e.g., 0.05 for 5%)"""
self.balance += self.balance * rate
return self.balance
# Usage
account = BankAccount(1000.50)
account.deposit(500.25)
account.add_interest(0.05)
print(f"Balance: ${account.balance:.2f}")
# Analyzing test scores
scores = [85.5, 92.0, 78.5, 88.5, 91.0]
def analyze_scores(scores):
total = sum(scores)
count = len(scores)
average = total / count
# Calculate standard deviation
variance = sum((x - average) ** 2 for x in scores) / count
std_dev = variance ** 0.5
return {
'average': average,
'max': max(scores),
'min': min(scores),
'std_dev': std_dev
}
results = analyze_scores(scores)
print(f"Average: {results['average']:.2f}")
print(f"Std Dev: {results['std_dev']:.2f}")
class TripCalculator:
def __init__(self):
self.total_distance = 0.0
self.total_fuel = 0.0
def add_trip(self, distance, fuel):
self.total_distance += distance
self.total_fuel += fuel
def average_efficiency(self):
if self.total_fuel == 0:
return 0.0
return self.total_distance / self.total_fuel
def cost_per_km(self, fuel_price):
if self.total_distance == 0:
return 0.0
total_cost = self.total_fuel * fuel_price
return total_cost / self.total_distance
# Usage
trips = TripCalculator()
trips.add_trip(350.5, 12.8) # 350.5 km, 12.8 L
trips.add_trip(280.2, 10.3) # 280.2 km, 10.3 L
print(f"Efficiency: {trips.average_efficiency():.2f} km/L")
print(f"Cost/km: ₹{trips.cost_per_km(105.50):.2f}")
class FitnessTracker:
def __init__(self, weight_kg):
self.weight = weight_kg
self.steps = 0
self.calories = 0.0
def walk(self, steps):
self.steps += steps
# Calories burned per step (approx)
calories_per_step = self.weight * 0.0005
self.calories += steps * calories_per_step
def run(self, distance_km):
# Calories burned per km running
calories_per_km = self.weight * 1.036
self.calories += distance_km * calories_per_km
# Rough steps estimate
self.steps += int(distance_km * 1300)
def get_stats(self):
return {
'weight': self.weight,
'steps': self.steps,
'calories': round(self.calories, 1),
'km_walked': round(self.steps * 0.0008, 2)
}
tracker = FitnessTracker(70.5)
tracker.walk(5000)
tracker.run(2.5)
print(tracker.get_stats())
⚠️ Common Mistakes with Floats
- Direct equality comparison:
0.1 + 0.2 == 0.3is False! Usemath.isclose() - Assuming float has infinite precision: Floats have about 15-17 decimal digits of precision
- Using float for currency: Can cause rounding errors in financial calculations - use
Decimal - int(float("12.5")) works, but int("12.5") doesn't: Remember the two-step conversion
- Not understanding truncation vs rounding:
int(3.9)is 3, not 4 - NaN comparison:
nan == nanis False! Usemath.isnan()
🔹 Best Practices with Floats
✅ DO
- Use
math.isclose()for comparisons - Use
Decimalfor financial calculations - Format floats for display:
f"{value:.2f}" - Be aware of precision limits
- Use
round()when you need rounding
❌ DON'T
- Don't compare floats directly with ==
- Don't use float for currency
- Don't assume exact representation
- Don't forget about precision limits
- Don't confuse int() with round()
✏️ Quick Practice
1. What is 0.1 + 0.2?
2. How to safely compare two floats?
3. What is int(3.9)?
4. Format 3.14159 to 2 decimals
5. What is 1.5e3?
6. Check if 3.0 is an integer
📌 Quick Reference
🎉 Chapter Summary
✅ float = numbers with decimals (3.14, -2.5, 1.0)
✅ Scientific notation: 1.5e3 = 1500.0, 2.5e-2 = 0.025
✅ Precision warning: 0.1 + 0.2 ≠ 0.3 exactly
✅ Use math.isclose() for comparing floats
✅ int() truncates (removes decimals), round() rounds
✅ Special values: inf, -inf, nan
✅ For money: use Decimal module, not float
9.3 Complex Numbers – Real + Imaginary (a + bj)
🔹 What are Complex Numbers?
Complex numbers are numbers that have both a real part and an imaginary part. They're written in the form a + bj, where j represents √(-1) (the imaginary unit). While they might seem abstract, they're essential in many fields of science and engineering!
Real Part
a in a + bj
Example: 5 in 5+3j
Imaginary Part
b in a + bj
Example: 3 in 5+3j
j = √(-1)
Imaginary unit
j² = -1
# Different ways to create complex numbers
z1 = 5 + 3j # Direct notation (j for imaginary)
z2 = 2 - 4j # Can be negative imaginary
z3 = complex(3, 2) # Using complex() function
z4 = 5j # Pure imaginary number
z5 = 7 + 0j # Real number as complex
print(f"z1 = {z1}")
print(f"z2 = {z2}")
print(f"z3 = {z3}")
print(f"z4 = {z4}")
print(f"z5 = {z5}")
# Access real and imaginary parts
print(f"Real part of z1: {z1.real}") # 5.0
print(f"Imag part of z1: {z1.imag}") # 3.0
print(f"Type: {type(z1)}") #
⚠️ Note: Use j not i for imaginary unit (engineering convention)
🔹 Complex Number Operations
z1 = 5 + 3j
z2 = 2 - 1j
# Addition
print(f"{z1} + {z2} = {z1 + z2}") # (7+2j)
# Subtraction
print(f"{z1} - {z2} = {z1 - z2}") # (3+4j)
# Multiplication
print(f"{z1} * {z2} = {z1 * z2}") # (13+1j)
# (5+3j)(2-1j) = 10 -5j +6j -3j² = 10 +j +3 = 13+1j
# Division
print(f"{z1} / {z2} = {z1 / z2}") # (1.4+2.2j)
# Exponentiation
print(f"{z1} ** 2 = {z1 ** 2}") # (16+30j)
import cmath # Complex math module
z = 3 + 4j
# Conjugate
print(f"conjugate of {z} = {z.conjugate()}") # (3-4j)
# Magnitude (absolute value)
print(f"|{z}| = {abs(z)}") # 5.0
# Phase (angle in radians)
print(f"phase = {cmath.phase(z)}") # 0.927...
# Polar coordinates (r, θ)
r, theta = cmath.polar(z)
print(f"polar: r={r}, θ={theta} rad")
# Convert from polar to rectangular
rect = cmath.rect(r, theta)
print(f"rectangular: {rect}")
import cmath
z = 2 + 2j
# Square root
print(f"√{z} = {cmath.sqrt(z)}") # (1.553+0.643j)
# Exponential
print(f"e^{z} = {cmath.exp(z)}") # (-3.074+6.719j)
# Logarithms
print(f"ln({z}) = {cmath.log(z)}") # (1.039+0.785j)
print(f"log10({z}) = {cmath.log10(z)}") # (0.451+0.341j)
# Trigonometric
print(f"sin({z}) = {cmath.sin(z)}") # (3.421-1.321j)
print(f"cos({z}) = {cmath.cos(z)}") # (-2.479-2.321j)
print(f"tan({z}) = {cmath.tan(z)}") # (-0.028+1.023j)
# Hyperbolic
print(f"sinh({z}) = {cmath.sinh(z)}") # (-1.509+2.287j)
z1 = 3 + 4j
z2 = 3 + 4j
z3 = 5 + 2j
# Equality (both real and imag must match)
print(f"{z1} == {z2}: {z1 == z2}") # True
print(f"{z1} == {z3}: {z1 == z3}") # False
# Cannot compare magnitude with > <
# z1 > z2 # TypeError!
# But you can compare magnitudes
print(f"|{z1}| > |{z3}|: {abs(z1) > abs(z3)}") # True
# Check if purely real
def is_real(z):
return z.imag == 0
# Check if purely imaginary
def is_imaginary(z):
return z.real == 0
print(f"{3+0j} is real: {is_real(3+0j)}") # True
print(f"{0+5j} is imaginary: {is_imaginary(5j)}") # True
🔹 Visualizing Complex Numbers
▲ Imaginary
│
4 │ ● (3,4)
│ /│
│ / │
│ / │
│/ │
└────┴────▶ Real
3
Real part: 3 (x-coordinate)
Imag part: 4 (y-coordinate)
Magnitude: √(3² + 4²) = 5
Phase angle: arctan(4/3) ≈ 53.13°
🔹 Real-World Applications
# AC Circuit Analysis
class ACComponent:
def __init__(self, resistance, reactance):
# Impedance = resistance + j * reactance
self.impedance = resistance + reactance * 1j
def current(self, voltage):
# Ohm's law for AC: I = V / Z
return voltage / self.impedance
def power(self, voltage):
# Complex power
i = self.current(voltage)
return voltage * i.conjugate()
# Resistor (pure resistance)
resistor = ACComponent(100, 0)
print(f"Resistor impedance: {resistor.impedance}Ω")
# Inductor (positive reactance)
inductor = ACComponent(0, 50)
print(f"Inductor impedance: {inductor.impedance}Ω")
# Capacitor (negative reactance)
capacitor = ACComponent(0, -30)
print(f"Capacitor impedance: {capacitor.impedance}Ω")
# Series circuit
voltage = 230 + 0j # 230V AC
total_z = resistor.impedance + inductor.impedance + capacitor.impedance
current = voltage / total_z
print(f"Current in series circuit: {current:.2f} A")
import cmath
import math
class SignalProcessor:
@staticmethod
def fourier_coefficient(signal, frequency, sampling_rate):
"""Compute Fourier coefficient at given frequency"""
N = len(signal)
coeff = 0j
for n, sample in enumerate(signal):
time = n / sampling_rate
# e^(-j*2π*f*t)
coeff += sample * cmath.exp(-2j * math.pi * frequency * time)
return coeff / N
@staticmethod
def magnitude_phase(complex_coeff):
"""Get magnitude and phase from complex coefficient"""
mag = abs(complex_coeff)
phase = cmath.phase(complex_coeff)
return mag, math.degrees(phase)
# Example: Analyze a simple sine wave
t = [i/100 for i in range(100)] # 0 to 1 second
signal = [math.sin(2 * math.pi * 5 * time) for time in t] # 5 Hz sine
coeff = SignalProcessor.fourier_coefficient(signal, 5, 100)
mag, phase = SignalProcessor.magnitude_phase(coeff)
print(f"Frequency 5Hz: magnitude={mag:.3f}, phase={phase:.1f}°")
# PID Controller with complex analysis
class TransferFunction:
def __init__(self, poles, zeros):
self.poles = poles
self.zeros = zeros
def evaluate(self, s):
"""Evaluate transfer function at complex frequency s"""
num = 1.0
for zero in self.zeros:
num *= (s - zero)
den = 1.0
for pole in self.poles:
den *= (s - pole)
return num / den
def stability(self):
"""Check if system is stable"""
# System is stable if all poles have negative real parts
for pole in self.poles:
if pole.real >= 0:
return False
return True
# Example: Simple low-pass filter
poles = [-10 + 10j, -10 - 10j] # Complex conjugate poles
zeros = [] # No zeros
lpf = TransferFunction(poles, zeros)
# Check at different frequencies
freqs = [0, 10, 100, 1000]
print("Frequency Response:")
for f in freqs:
s = 2j * math.pi * f # s = jω
response = lpf.evaluate(s)
mag = abs(response)
phase = cmath.phase(response)
print(f"f={f}Hz: mag={mag:.3f}, phase={math.degrees(phase):.1f}°")
print(f"System stable: {lpf.stability()}")
import cmath
import math
class AudioProcessor:
@staticmethod
def create_complex_signal(frequency, duration, sample_rate=44100):
"""Create a complex exponential signal"""
samples = int(duration * sample_rate)
signal = []
for n in range(samples):
t = n / sample_rate
# e^(j*2π*f*t) = cos + j*sin
signal.append(cmath.exp(2j * math.pi * frequency * t))
return signal
@staticmethod
def modulate(signal, carrier_freq, sample_rate):
"""Modulate signal with carrier"""
modulated = []
for n, sample in enumerate(signal):
t = n / sample_rate
carrier = cmath.exp(2j * math.pi * carrier_freq * t)
modulated.append(sample * carrier)
return modulated
@staticmethod
def extract_envelope(signal):
"""Extract magnitude envelope"""
return [abs(s) for s in signal]
# Example: Create and modulate a tone
tone = AudioProcessor.create_complex_signal(440, 0.01) # 440Hz, 10ms
modulated = AudioProcessor.modulate(tone, 1000, 44100) # Modulate to 1kHz
print(f"Original signal (first 5 samples):")
for i in range(5):
print(f" {tone[i]:.3f}")
print(f"\nModulated signal (first 5 samples):")
for i in range(5):
print(f" {modulated[i]:.3f}")
🔹 Advanced Mathematical Applications
def mandelbrot(c, max_iter=100):
"""Check if point c is in Mandelbrot set"""
z = 0
for n in range(max_iter):
z = z * z + c
if abs(z) > 2:
return n
return max_iter
# Generate Mandelbrot set
width, height = 80, 24
for y in range(height):
row = ""
for x in range(width):
# Map to complex plane
real = (x - width/2) * 4 / width
imag = (y - height/2) * 4 / height
c = complex(real, imag)
iter_count = mandelbrot(c)
if iter_count == 100:
row += "*"
elif iter_count > 80:
row += "."
else:
row += " "
print(row)
import cmath
def solve_quadratic(a, b, c):
"""Solve quadratic equation ax² + bx + c = 0"""
# Calculate discriminant
d = (b**2) - (4*a*c)
# Find two solutions
sol1 = (-b - cmath.sqrt(d)) / (2*a)
sol2 = (-b + cmath.sqrt(d)) / (2*a)
return sol1, sol2
# Examples
print("Equation: x² + 2x + 5 = 0")
s1, s2 = solve_quadratic(1, 2, 5)
print(f"Solutions: {s1}, {s2}")
print("\nEquation: x² - 4x + 13 = 0")
s1, s2 = solve_quadratic(1, -4, 13)
print(f"Solutions: {s1}, {s2}")
print("\nEquation: 2x² - 7x + 5 = 0")
s1, s2 = solve_quadratic(2, -7, 5)
print(f"Solutions: {s1:.2f}, {s2:.2f}")
import cmath
import math
# Euler's formula: e^(jθ) = cos(θ) + j·sin(θ)
theta = math.pi / 4 # 45 degrees
# Using Euler's formula
euler = cmath.exp(1j * theta)
# Direct calculation
cos_theta = math.cos(theta)
sin_theta = math.sin(theta)
direct = complex(cos_theta, sin_theta)
print(f"θ = {math.degrees(theta)}°")
print(f"e^(jθ) = {euler}")
print(f"cosθ + j·sinθ = {direct}")
print(f"Equal: {abs(euler - direct) < 1e-10}")
# Magnitude should be 1
print(f"|e^(jθ)| = {abs(euler)}")
import cmath
import math
def roots_of_unity(n):
"""Find all n-th roots of unity"""
roots = []
for k in range(n):
# e^(2πi·k/n)
angle = 2 * math.pi * k / n
root = cmath.exp(1j * angle)
roots.append(root)
return roots
# Find cube roots of unity
n = 3
roots = roots_of_unity(n)
print(f"{n}th roots of unity:")
for i, root in enumerate(roots):
print(f" ω{i} = {root:.4f}")
print(f" (ω{i})³ = {root**3:.4f}")
# Verify sum is zero
sum_roots = sum(roots)
print(f"\nSum of all roots: {sum_roots:.4f}")
🔹 Complex Number Functions Reference
| Function | Description | Example | Result |
|---|---|---|---|
z.real |
Real part | (3+4j).real |
3.0 |
z.imag |
Imaginary part | (3+4j).imag |
4.0 |
z.conjugate() |
Complex conjugate | (3+4j).conjugate() |
(3-4j) |
abs(z) |
Magnitude/modulus | abs(3+4j) |
5.0 |
cmath.phase(z) |
Phase angle (radians) | cmath.phase(3+4j) |
0.927... |
cmath.polar(z) |
Convert to polar | cmath.polar(3+4j) |
(5.0, 0.927...) |
cmath.rect(r, phi) |
Convert from polar | cmath.rect(5, 0.927) |
(3+4j) |
cmath.exp(z) |
Exponential e^z | cmath.exp(1j*math.pi) |
(-1+0j) |
cmath.sqrt(z) |
Square root | cmath.sqrt(-1) |
1j |
⚠️ Common Mistakes with Complex Numbers
- Using i instead of j: Python uses
jfor imaginary unit, noti - Can't convert directly:
int(z)orfloat(z)raise TypeError - Can't compare with > or <: Complex numbers aren't ordered - use
abs()for magnitude - Forgetting to import cmath: Math functions for complex are in
cmath, notmath - Assuming real part is float:
z.realreturns float, not int - Multiplication confusion:
j*j = -1(not j² = -1, it's -1!)
✔ Where Complex Numbers Are Essential
⚡ Electrical Engineering
AC circuit analysis, impedance, phasors
📡 Signal Processing
Fourier transforms, filters, modulation
🔊 Audio Engineering
Frequency analysis, sound synthesis
🔬 Quantum Physics
Wave functions, Schrödinger equation
🤖 Control Theory
Transfer functions, stability analysis
🎨 Fractal Geometry
Mandelbrot set, Julia sets
✏️ Quick Practice
1. Create complex number 3 - 2j
2. Get real part of 5+12j
3. Find magnitude of 3+4j
4. Conjugate of 2-7j
5. What's (2+3j) + (1-2j)?
6. Square root of -1
📌 Quick Reference
🎉 Chapter Summary
✅ Complex numbers = a + bj (real + imaginary)
✅ Access parts: z.real, z.imag
✅ Conjugate: z.conjugate() flips imaginary sign
✅ Magnitude: abs(z) = √(a² + b²)
✅ Phase angle: cmath.phase(z) in radians
✅ Use cmath for advanced functions (sqrt, exp, trig)
✅ Applications: Electrical, signal processing, quantum physics
✅ Cannot convert directly to int or float
9.4 Useful Number Functions in Python
🔹 What are Built-in Number Functions?
Python provides a rich set of built-in functions that work with numbers. These functions are always available – you don't need to import any modules. They make common mathematical operations easy and efficient!
abs()
Absolute value
pow()
Power/exponent
round()
Rounding
max()/min()
Find extremes
🔹 abs() – Absolute Value
abs(x) – Returns the absolute value (distance from zero) of x.
# Absolute value of integers
print(f"abs(10) = {abs(10)}") # 10
print(f"abs(-10) = {abs(-10)}") # 10
print(f"abs(0) = {abs(0)}") # 0
print(f"abs(-5) = {abs(-5)}") # 5
print(f"abs(-1000) = {abs(-1000)}") # 1000
# Useful for distance calculations
position = -15
distance = abs(position)
print(f"Distance from zero: {distance}")
# Absolute value of floats
print(f"abs(3.14) = {abs(3.14)}") # 3.14
print(f"abs(-2.5) = {abs(-2.5)}") # 2.5
print(f"abs(-0.001) = {abs(-0.001)}") # 0.001
# With complex numbers (magnitude)
z = 3 + 4j
print(f"abs({z}) = {abs(z)}") # 5.0
print(f"abs(1+1j) = {abs(1+1j)}") # 1.414...
# Real-world: temperature difference
temp1 = -5
temp2 = 10
temp_diff = abs(temp1 - temp2)
print(f"Temperature difference: {temp_diff}°C")
🔹 pow() – Power/Exponentiation
pow(x, y) – Returns x raised to the power y (xʸ).
# Simple powers
print(f"pow(2, 3) = {pow(2, 3)}") # 8
print(f"pow(5, 2) = {pow(5, 2)}") # 25
print(f"pow(10, 4) = {pow(10, 4)}") # 10000
# Negative exponents (float results)
print(f"pow(2, -1) = {pow(2, -1)}") # 0.5
print(f"pow(5, -2) = {pow(5, -2)}") # 0.04
# Zero exponents
print(f"pow(5, 0) = {pow(5, 0)}") # 1
print(f"pow(0, 5) = {pow(0, 5)}") # 0
# With floats
print(f"pow(2.5, 2) = {pow(2.5, 2)}") # 6.25
# pow() with 3 arguments (modular exponentiation)
# pow(x, y, z) = (xʸ) % z (more efficient for large numbers)
print(f"pow(2, 3, 5) = {pow(2, 3, 5)}") # 8 % 5 = 3
print(f"pow(7, 4, 10) = {pow(7, 4, 10)}") # 2401 % 10 = 1
# Useful in cryptography
base = 123456789
exp = 987654321
mod = 1000000
result = pow(base, exp, mod)
print(f"Modular exponent result: {result}")
# pow() vs ** operator
print(f"2 ** 3 = {2 ** 3}") # 8
print(f"pow(2, 3) = {pow(2, 3)}") # 8
# pow() can handle modular arithmetic, ** cannot
pow(x, y, z) is more efficient than (x**y) % z for large numbers.
🔹 round() – Rounding Numbers
round(number, ndigits) – Rounds number to ndigits decimal places.
# Round to nearest integer
print(f"round(3.14) = {round(3.14)}") # 3
print(f"round(3.76) = {round(3.76)}") # 4
print(f"round(4.5) = {round(4.5)}") # 4 (bankers rounding)
print(f"round(5.5) = {round(5.5)}") # 6 (bankers rounding)
# Negative numbers
print(f"round(-3.14) = {round(-3.14)}") # -3
print(f"round(-3.76) = {round(-3.76)}") # -4
# Bankers rounding (rounds to nearest even)
print(f"round(2.5) = {round(2.5)}") # 2
print(f"round(3.5) = {round(3.5)}") # 4
# Round to specific decimal places
pi = 3.14159265359
print(f"π to 2 decimals: {round(pi, 2)}") # 3.14
print(f"π to 3 decimals: {round(pi, 3)}") # 3.142
print(f"π to 4 decimals: {round(pi, 4)}") # 3.1416
# With negative ndigits (rounding to tens, hundreds)
num = 12345
print(f"round(12345, -1) = {round(12345, -1)}") # 12340
print(f"round(12345, -2) = {round(12345, -2)}") # 12300
print(f"round(12345, -3) = {round(12345, -3)}") # 12000
# Real-world: currency formatting
price = 49.995
print(f"Price: ${round(price, 2)}") # $50.0 (actually 50.0, need formatting)
decimal module.
🔹 max() and min() – Find Extremes
max(x1, x2, ...) or max(iterable) – Returns largest value.min(x1, x2, ...) or min(iterable) – Returns smallest value.
# With multiple arguments
print(f"max(2, 8, 1, 5, 3) = {max(2, 8, 1, 5, 3)}") # 8
print(f"max(-5, -2, -10) = {max(-5, -2, -10)}") # -2
print(f"max(3.14, 2.7, 1.59) = {max(3.14, 2.7, 1.59)}") # 3.14
# With lists
numbers = [45, 67, 23, 89, 12]
print(f"max({numbers}) = {max(numbers)}") # 89
# With strings (lexicographic comparison)
words = ["apple", "banana", "cherry"]
print(f"max({words}) = {max(words)}") # "cherry" (by alphabetical)
# With key function
students = [("Rahul", 85), ("Priya", 92), ("Amit", 78)]
highest_score = max(students, key=lambda s: s[1])
print(f"Highest scorer: {highest_score}")
# With multiple arguments
print(f"min(2, 8, 1, 5, 3) = {min(2, 8, 1, 5, 3)}") # 1
print(f"min(-5, -2, -10) = {min(-5, -2, -10)}") # -10
print(f"min(3.14, 2.7, 1.59) = {min(3.14, 2.7, 1.59)}") # 1.59
# With lists
numbers = [45, 67, 23, 89, 12]
print(f"min({numbers}) = {min(numbers)}") # 12
# With strings
words = ["apple", "banana", "cherry"]
print(f"min({words}) = {min(words)}") # "apple"
# Finding closest to zero
def closest_to_zero(numbers):
return min(numbers, key=abs)
values = [-5, 3, -2, 7, -1]
closest = closest_to_zero(values)
print(f"Closest to zero: {closest}") # -1
🔹 Additional Useful Number Functions
# Returns (quotient, remainder)
q, r = divmod(17, 5)
print(f"17 ÷ 5 = {q} remainder {r}")
# Useful for time conversion
seconds = 3665
minutes, secs = divmod(seconds, 60)
hours, minutes = divmod(minutes, 60)
print(f"{hours}h {minutes}m {secs}s")
# Sum of all elements
numbers = [1, 2, 3, 4, 5]
print(f"sum({numbers}) = {sum(numbers)}") # 15
# With start value
print(f"sum with start 10: {sum(numbers, 10)}") # 25
# Average calculation
avg = sum(numbers) / len(numbers)
print(f"Average: {avg}")
# Check if value is a number type
x = 10
print(f"x is int: {isinstance(x, int)}") # True
print(f"x is float: {isinstance(x, float)}") # False
# Check multiple types
from numbers import Number
print(f"x is number: {isinstance(x, Number)}") # True
numbers = [5, 2, 8, 1, 9]
print(f"Sorted ascending: {sorted(numbers)}")
print(f"Sorted descending: {sorted(numbers, reverse=True)}")
# Count elements (for sequences)
numbers = [1, 2, 3, 4, 5]
print(f"Length: {len(numbers)}") # 5
# Number of digits in integer
num = 12345
digits = len(str(num))
print(f"{num} has {digits} digits")
# Format numbers for display
pi = 3.14159
print(format(pi, ".2f")) # "3.14"
print(format(1234567, ",")) # "1,234,567"
print(format(0.25, ".1%")) # "25.0%"
🔹 Complete Built-in Number Functions Reference
| Function | Description | Example | Result | Use Case |
|---|---|---|---|---|
abs(x) |
Absolute value | abs(-5) |
5 | Distance, magnitude |
pow(x, y) |
x raised to power y | pow(2, 3) |
8 | Exponentiation |
pow(x, y, z) |
(xʸ) % z | pow(2, 3, 5) |
3 | Cryptography |
round(x, n) |
Round to n decimals | round(3.14159, 2) |
3.14 | Formatting |
max(x1, x2, ...) |
Largest value | max(2,8,1) |
8 | Find maximum |
min(x1, x2, ...) |
Smallest value | min(2,8,1) |
1 | Find minimum |
sum(iterable) |
Sum of all items | sum([1,2,3,4]) |
10 | Totals |
divmod(a, b) |
Quotient and remainder | divmod(17,5) |
(3,2) | Time/distance conversion |
len(s) |
Length of sequence | len([1,2,3]) |
3 | Count items |
sorted(iterable) |
Sorted list | sorted([3,1,2]) |
[1,2,3] | Ordering |
isinstance(x, type) |
Check type | isinstance(5, int) |
True | Type checking |
format(x, spec) |
Format number | format(3.14, ".2f") |
"3.14" | Display formatting |
🔹 Real-World Applications
# Analyze test scores
scores = [85, 92, 78, 88, 95, 67, 89]
highest = max(scores)
lowest = min(scores)
average = sum(scores) / len(scores)
range_score = highest - lowest
print(f"Highest: {highest}")
print(f"Lowest: {lowest}")
print(f"Average: {round(average, 2)}")
print(f"Range: {range_score}")
# Find students near average
near_avg = [s for s in scores if abs(s - average) < 5]
print(f"Near average: {near_avg}")
# Investment returns
def compound_interest(principal, rate, years):
return round(principal * pow(1 + rate, years), 2)
investment = 10000
rate = 0.08
years = 10
future_value = compound_interest(investment, rate, years)
print(f"${investment} at {rate*100}% for {years} years = ${future_value}")
# Loan payment calculation
loan = 50000
interest_rate = 0.05
months = 60
monthly_payment = (loan * interest_rate/12 * pow(1+interest_rate/12, months)) / (pow(1+interest_rate/12, months) - 1)
print(f"Monthly payment: ${round(monthly_payment, 2)}")
# Simple statistical functions
data = [12, 15, 18, 21, 24, 27, 30]
def mean(data):
return sum(data) / len(data)
def median(data):
sorted_data = sorted(data)
n = len(sorted_data)
mid = n // 2
if n % 2 == 0:
return (sorted_data[mid-1] + sorted_data[mid]) / 2
return sorted_data[mid]
def range_stat(data):
return max(data) - min(data)
print(f"Mean: {round(mean(data), 2)}")
print(f"Median: {median(data)}")
print(f"Range: {range_stat(data)}")
# Convert seconds to readable format
def format_time(seconds):
minutes, secs = divmod(seconds, 60)
hours, minutes = divmod(minutes, 60)
days, hours = divmod(hours, 24)
parts = []
if days > 0:
parts.append(f"{days} day{'s' if days>1 else ''}")
if hours > 0:
parts.append(f"{hours} hour{'s' if hours>1 else ''}")
if minutes > 0:
parts.append(f"{minutes} minute{'s' if minutes>1 else ''}")
if secs > 0:
parts.append(f"{secs} second{'s' if secs>1 else ''}")
return ", ".join(parts)
print(format_time(3665)) # 1 hour, 1 minute, 5 seconds
print(format_time(90061)) # 1 day, 1 hour, 1 minute, 1 second
⚠️ Common Mistakes
- round() behavior: Python uses "bankers rounding" (round half to even) –
round(2.5) = 2, not 3! - pow() vs **: For large numbers with modulus, always use
pow(x, y, z)– it's much faster - max() with strings: Compares lexicographically, not numerically –
"10"is less than"2" - abs() with complex: Returns magnitude, not the real part –
abs(3+4j) = 5.0 - divmod() with negatives: Results can be surprising –
divmod(-17, 5) = (-4, 3) - sum() with non-numbers: Will raise TypeError – can't sum strings directly
🔹 Best Practices
✅ DO
- Use
pow(x, y, z)for modular exponentiation - Use
divmod()for quotient and remainder - Use
round(x, 2)for currency display - Use
max()with key for custom comparisons - Check types with
isinstance()before operations
❌ DON'T
- Don't assume round(2.5) = 3 (it's 2!)
- Don't use
**and%separately for large exponents - Don't compare strings with numbers using max()
- Don't forget abs() for distance calculations
- Don't use sum() on non-numeric collections
✏️ Quick Practice
1. What is abs(-15)?
2. pow(3, 3) = ?
3. round(4.5) = ? (in Python)
4. max(10, 20, 5) = ?
5. divmod(17, 5) returns?
6. sum([1, 2, 3, 4, 5]) = ?
📌 Quick Reference
🎉 Chapter Summary
✅ abs(x) = distance from zero (always non-negative)
✅ pow(x, y) = xʸ, pow(x, y, z) = (xʸ) % z (efficient!)
✅ round(x, n) = rounds to n decimals (bankers rounding for .5)
✅ max()/min() = find largest/smallest values
✅ divmod(a, b) = (a÷b, a%b) as tuple
✅ sum() = total of all items in iterable
✅ len() = number of items (or digits after str conversion)
✅ All are built-in – no import needed!
9.5 Math Module – Easy Mathematical Operations
🔹 What is the Math Module?
Python's math module provides access to advanced mathematical functions and constants
beyond basic arithmetic. It's like having a scientific calculator built into Python!
You need to import math first to use these functions.
Roots & Powers
sqrt, pow, exp
Rounding
ceil, floor, trunc
Trigonometry
sin, cos, tan
Logarithms
log, log10, log2
import math # Now all math functions are available
# You can also import specific functions
from math import sqrt, pi # import only what you need
# Or import with alias
import math as m # use m.sqrt(), m.pi, etc.
⚠️ You must import the module before using any of its functions!
🔹 Basic Mathematical Functions
import math
# Square root
print(f"math.sqrt(16) = {math.sqrt(16)}") # 4.0
print(f"math.sqrt(25) = {math.sqrt(25)}") # 5.0
print(f"math.sqrt(2) = {math.sqrt(2):.4f}") # 1.4142
print(f"math.sqrt(0) = {math.sqrt(0)}") # 0.0
# Power (exponentiation)
print(f"math.pow(2, 3) = {math.pow(2, 3)}") # 8.0
print(f"math.pow(5, 2) = {math.pow(5, 2)}") # 25.0
print(f"math.pow(10, -2) = {math.pow(10, -2)}") # 0.01
# Note: math.pow() always returns float
# Compare with built-in pow() and ** operator
print(f"2 ** 3 = {2 ** 3}") # 8 (int)
import math
# Factorial (n!)
print(f"math.factorial(5) = {math.factorial(5)}") # 120
print(f"math.factorial(7) = {math.factorial(7)}") # 5040
print(f"math.factorial(10) = {math.factorial(10)}") # 3628800
# Gamma function (generalized factorial)
print(f"math.gamma(5) = {math.gamma(5)}") # 24.0 (same as 4!)
print(f"math.gamma(5.5) = {math.gamma(5.5):.2f}") # 52.34
# Factorial grows fast!
print(f"20! = {math.factorial(20)}") # 2432902008176640000
# Useful in probability and combinatorics
import math
# Exponential (e^x)
print(f"math.exp(1) = {math.exp(1)}") # 2.71828 (e)
print(f"math.exp(2) = {math.exp(2):.2f}") # 7.39
print(f"math.exp(-1) = {math.exp(-1):.3f}") # 0.368
# Exponential minus 1 (more accurate for small x)
print(f"math.expm1(0.001) = {math.expm1(0.001):.6f}") # 0.0010005
# 2^x and e^x
x = 3
print(f"e^{x} = {math.exp(x):.2f}")
print(f"2^{x} = {math.pow(2, x)}")
# Used in growth calculations, compound interest
import math
# Absolute value (same as built-in abs)
print(f"math.fabs(-5) = {math.fabs(-5)}") # 5.0
print(f"math.fabs(-3.14) = {math.fabs(-3.14)}") # 3.14
# Remainder (different from %)
print(f"math.fmod(17, 5) = {math.fmod(17, 5)}") # 2.0
print(f"17 % 5 = {17 % 5}") # 2
# Sum of products (useful for dot products)
print(f"math.fsum([0.1, 0.2, 0.3]) = {math.fsum([0.1, 0.2, 0.3])}")
print(f"sum([0.1, 0.2, 0.3]) = {sum([0.1, 0.2, 0.3])}")
# fsum is more accurate for floating point sums
🔹 Rounding Functions
import math
# ceil() always rounds UP to nearest integer
print(f"math.ceil(3.1) = {math.ceil(3.1)}") # 4
print(f"math.ceil(3.9) = {math.ceil(3.9)}") # 4
print(f"math.ceil(4.0) = {math.ceil(4.0)}") # 4
print(f"math.ceil(-3.1) = {math.ceil(-3.1)}") # -3 (rounds UP)
print(f"math.ceil(-3.9) = {math.ceil(-3.9)}") # -3
# Real-world: ceiling function for pricing
items = 17
box_size = 5
boxes_needed = math.ceil(items / box_size)
print(f"Need {boxes_needed} boxes for {items} items")
import math
# floor() always rounds DOWN to nearest integer
print(f"math.floor(3.1) = {math.floor(3.1)}") # 3
print(f"math.floor(3.9) = {math.floor(3.9)}") # 3
print(f"math.floor(4.0) = {math.floor(4.0)}") # 4
print(f"math.floor(-3.1) = {math.floor(-3.1)}") # -4 (rounds DOWN)
print(f"math.floor(-3.9) = {math.floor(-3.9)}") # -4
# Real-world: floor function for pagination
total_items = 47
items_per_page = 10
total_pages = math.floor(total_items / items_per_page)
print(f"Full pages: {total_pages}, remaining: {total_items % items_per_page}")
import math
# trunc() removes decimal part (toward zero)
print(f"math.trunc(3.1) = {math.trunc(3.1)}") # 3
print(f"math.trunc(3.9) = {math.trunc(3.9)}") # 3
print(f"math.trunc(-3.1) = {math.trunc(-3.1)}") # -3
print(f"math.trunc(-3.9) = {math.trunc(-3.9)}") # -3
# Compare trunc with floor and ceil
values = [3.1, 3.9, -3.1, -3.9]
for v in values:
print(f"{v:5} → trunc: {math.trunc(v):2}, floor: {math.floor(v):2}, ceil: {math.ceil(v):2}")
import math
# Summary of rounding functions
x = 3.7
print(f"Original: {x}")
print(f"round() : {round(x)}") # 4
print(f"ceil() : {math.ceil(x)}") # 4
print(f"floor() : {math.floor(x)}") # 3
print(f"trunc() : {math.trunc(x)}") # 3
x = -3.7
print(f"\nOriginal: {x}")
print(f"round() : {round(x)}") # -4
print(f"ceil() : {math.ceil(x)}") # -3 (up)
print(f"floor() : {math.floor(x)}") # -4 (down)
print(f"trunc() : {math.trunc(x)}") # -3 (toward zero)
🔹 Trigonometric Functions
import math
# Convert degrees to radians
degrees = 90
radians = math.radians(degrees)
print(f"{degrees}° = {radians:.4f} rad")
# sin, cos, tan
angle = math.radians(30) # 30 degrees
print(f"sin(30°) = {math.sin(angle):.4f}") # 0.5
print(f"cos(30°) = {math.cos(angle):.4f}") # 0.8660
print(f"tan(30°) = {math.tan(angle):.4f}") # 0.5774
# Special angles
print(f"sin(90°) = {math.sin(math.pi/2):.0f}") # 1.0
print(f"cos(0°) = {math.cos(0):.0f}") # 1.0
import math
# Inverse trig functions (arcsin, arccos, arctan)
x = 0.5
print(f"asin(0.5) = {math.asin(x):.4f} rad") # 0.5236 rad
print(f"asin(0.5) = {math.degrees(math.asin(x)):.1f}°") # 30.0°
y = 1.0
print(f"acos(1) = {math.acos(y):.0f} rad") # 0 rad
print(f"atan(1) = {math.atan(1):.4f} rad") # 0.7854 rad
# atan2 (useful for converting coordinates)
print(f"atan2(1,1) = {math.atan2(1,1):.4f} rad") # 0.7854 rad
import math
# hypot() calculates hypotenuse (sqrt(x² + y²))
print(f"hypot(3,4) = {math.hypot(3,4)}") # 5.0
print(f"hypot(5,12) = {math.hypot(5,12)}") # 13.0
# Distance between two points
def distance(x1, y1, x2, y2):
return math.hypot(x2 - x1, y2 - y1)
print(f"Distance: {distance(0,0,3,4):.2f}") # 5.0
# 3D distance
def distance3d(x1, y1, z1, x2, y2, z2):
dx = x2 - x1
dy = y2 - y1
dz = z2 - z1
return math.sqrt(dx*dx + dy*dy + dz*dz)
print(f"3D distance: {distance3d(0,0,0,1,1,1):.2f}") # 1.73
import math
# Hyperbolic functions
x = 1.0
print(f"sinh({x}) = {math.sinh(x):.4f}") # 1.1752
print(f"cosh({x}) = {math.cosh(x):.4f}") # 1.5431
print(f"tanh({x}) = {math.tanh(x):.4f}") # 0.7616
# Inverse hyperbolic
print(f"asinh(1) = {math.asinh(1):.4f}") # 0.8814
print(f"acosh(2) = {math.acosh(2):.4f}") # 1.3170
print(f"atanh(0.5) = {math.atanh(0.5):.4f}") # 0.5493
🔹 Logarithmic Functions
import math
# Natural logarithm (base e)
print(f"math.log(10) = {math.log(10):.4f}") # 2.3026
print(f"math.log(e) = {math.log(math.e):.0f}") # 1.0
print(f"math.log(1) = {math.log(1):.0f}") # 0.0
# Log base 10
print(f"math.log10(100) = {math.log10(100):.0f}") # 2.0
print(f"math.log10(1000) = {math.log10(1000):.0f}") # 3.0
print(f"math.log10(2) = {math.log10(2):.4f}") # 0.3010
# Log with custom base
print(f"math.log(8, 2) = {math.log(8, 2):.0f}") # 3.0
print(f"math.log(27, 3) = {math.log(27, 3):.0f}") # 3.0
import math
# log1p(x) = log(1+x) more accurate for small x
x = 1e-5
print(f"log(1+{x}) = {math.log(1+x):.10f}")
print(f"log1p({x}) = {math.log1p(x):.10f}") # More accurate
# Log base 2
print(f"math.log2(1024) = {math.log2(1024):.0f}") # 10.0
print(f"math.log2(8) = {math.log2(8):.0f}") # 3.0
# Information theory - bits needed
alphabet_size = 26
bits_needed = math.log2(alphabet_size)
print(f"Need {math.ceil(bits_needed)} bits for {alphabet_size} symbols")
🔹 Mathematical Constants
π (pi)
π
math.pi
3.141592653589793
e
e
math.e
2.718281828459045
τ (tau)
τ
math.tau
6.283185307179586
Infinity
∞
math.inf
inf
import math
# Circle calculations
radius = 5
area = math.pi * radius ** 2
circumference = 2 * math.pi * radius
print(f"Circle area: {area:.2f}")
print(f"Circumference: {circumference:.2f}")
# Using tau (2π)
print(f"Tau = {math.tau:.6f}")
print(f"2π = {2 * math.pi:.6f}") # Same as tau
# Euler's number
print(f"e^2 = {math.e ** 2:.4f}")
print(f"exp(2) = {math.exp(2):.4f}") # Same thing
🔹 Complete Math Module Reference
| Category | Function | Description | Example | Result |
|---|---|---|---|---|
| Number Theory | math.ceil(x) |
Round up | math.ceil(3.1) |
4 |
math.floor(x) |
Round down | math.floor(3.9) |
3 | |
math.trunc(x) |
Truncate toward zero | math.trunc(-3.9) |
-3 | |
math.fabs(x) |
Absolute value (float) | math.fabs(-5) |
5.0 | |
| Power & Logs | math.sqrt(x) |
Square root | math.sqrt(16) |
4.0 |
math.pow(x, y) |
x raised to y (float) | math.pow(2, 3) |
8.0 | |
math.exp(x) |
e^x | math.exp(1) |
2.71828 | |
math.log(x) |
Natural log | math.log(10) |
2.3026 | |
math.log10(x) |
Log base 10 | math.log10(100) |
2.0 | |
| Trigonometry | math.sin(x) |
Sine (radians) | math.sin(math.pi/2) |
1.0 |
math.cos(x) |
Cosine (radians) | math.cos(0) |
1.0 | |
math.tan(x) |
Tangent (radians) | math.tan(math.pi/4) |
1.0 | |
math.asin(x) |
Arc sine | math.asin(0.5) |
0.5236 | |
math.acos(x) |
Arc cosine | math.acos(1) |
0.0 | |
math.atan(x) |
Arc tangent | math.atan(1) |
0.7854 | |
| Angles | math.degrees(x) |
Radians → degrees | math.degrees(math.pi) |
180.0 |
math.radians(x) |
Degrees → radians | math.radians(180) |
3.14159 | |
math.hypot(x, y) |
Hypotenuse √(x²+y²) | math.hypot(3,4) |
5.0 | |
| Constants | math.pi |
π (3.14159...) | math.pi |
3.14159 |
math.e |
e (2.71828...) | math.e |
2.71828 | |
math.tau |
τ (6.28318...) | math.tau |
6.28318 | |
math.inf |
Infinity | math.inf |
inf |
🔹 Real-World Applications
import math
# Calculate standard deviation
def standard_deviation(data):
n = len(data)
mean = sum(data) / n
variance = sum((x - mean) ** 2 for x in data) / (n - 1)
return math.sqrt(variance)
scores = [85, 92, 78, 88, 95, 67, 89]
std_dev = standard_deviation(scores)
print(f"Standard deviation: {std_dev:.2f}")
# Normal distribution (simplified)
def normal_pdf(x, mean=0, std=1):
return (1 / (std * math.sqrt(2 * math.pi))) * math.exp(-0.5 * ((x - mean) / std) ** 2)
print(f"N(0,1) at x=0: {normal_pdf(0):.4f}")
import math
# Compound interest
def compound_interest(principal, rate, time, n):
"""A = P(1 + r/n)^(nt)"""
return principal * math.pow(1 + rate/n, n * time)
# Continuous compounding
def continuous_interest(principal, rate, time):
"""A = P * e^(rt)"""
return principal * math.exp(rate * time)
investment = 10000
rate = 0.08
years = 10
future_value = compound_interest(investment, rate, years, 12)
continuous = continuous_interest(investment, rate, years)
print(f"Monthly compounding: ${future_value:.2f}")
print(f"Continuous compounding: ${continuous:.2f}")
import math
# Calculate distance between two points on Earth (Haversine formula)
def haversine(lat1, lon1, lat2, lon2):
R = 6371 # Earth's radius in km
phi1 = math.radians(lat1)
phi2 = math.radians(lat2)
dphi = math.radians(lat2 - lat1)
dlambda = math.radians(lon2 - lon1)
a = math.sin(dphi/2)**2 + math.cos(phi1) * math.cos(phi2) * math.sin(dlambda/2)**2
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a))
return R * c
# Distance between New York and London
ny_lat, ny_lon = 40.7128, -74.0060
london_lat, london_lon = 51.5074, -0.1278
distance = haversine(ny_lat, ny_lon, london_lat, london_lon)
print(f"NY to London distance: {distance:.0f} km")
import math
# Generate sine wave
def generate_sine_wave(frequency, duration, sample_rate=44100):
samples = int(duration * sample_rate)
wave = []
for i in range(samples):
t = i / sample_rate
value = math.sin(2 * math.pi * frequency * t)
wave.append(value)
return wave
# Calculate signal power
def signal_power(signal):
return math.sqrt(sum(x**2 for x in signal) / len(signal))
# Generate 1 second of 440 Hz sine wave
wave = generate_sine_wave(440, 1.0)
power = signal_power(wave)
print(f"Signal power: {power:.4f}")
# Fourier series approximation of square wave
def square_wave(t, n_terms=5):
result = 0
for n in range(1, n_terms*2, 2):
result += (4 / (math.pi * n)) * math.sin(2 * math.pi * n * t)
return result
⚠️ Common Mistakes
- Forgetting to import math: Using
math.sqrt(16)without import raises NameError - Using degrees instead of radians:
math.sin(90)gives sin(90 radians), not sin(90°) - math.pow() always returns float: Unlike built-in pow() which can return int
- Domain errors:
math.sqrt(-1)raises ValueError (use cmath for complex) - math.log(0) or math.log(-1): Raises ValueError (undefined)
- Confusing ceil and floor for negatives: ceil(-3.1) = -3, floor(-3.1) = -4
🔹 math vs cmath vs Built-in Functions
Built-in
Always available, no import needed
abs(),pow(),round()max(),min(),sum()- Works with all numeric types
math module
Advanced real-number math
math.sqrt(),math.sin()math.log(),math.exp()- Floats only, real numbers
cmath module
Complex number math
cmath.sqrt(-1)→ 1jcmath.exp(1j*math.pi)→ -1- Works with complex numbers
✏️ Quick Practice
1. Square root of 144?
2. Round 3.2 up and down?
3. sin(90°) in radians?
4. log10(1000)?
5. Value of π?
6. Hypotenuse of 5,12?
📌 Quick Reference
🎉 Chapter Summary
✅ math module provides advanced mathematical functions
✅ Must import: import math before using
✅ Rounding: ceil (up), floor (down), trunc (toward zero)
✅ Trigonometry: sin, cos, tan – use radians not degrees
✅ Constants: math.pi, math.e, math.tau, math.inf
✅ Logs: log() (natural), log10(), log2()
✅ Powers & roots: sqrt(), pow(), exp()
✅ Real-world use: Statistics, finance, geometry, signal processing
🎓 Module 09 : Python Number (int, float, complex) Successfully Completed
You have successfully completed this module of Python for Cybersecurity.
Keep building your expertise step by step — Learn Next Module →
🔤 Python Strings – The Complete Master Guide
📚 10.1 What is a String? – The Complete Guide
A string is a sequence of characters (letters, numbers, symbols, spaces) enclosed in quotes. In Python, strings are immutable – once created, they cannot be changed. Any operation that modifies a string creates a new string.
📖 Real-World Analogy
- 🏷️ Name tag: Once printed, you can't change it (immutable)
- 📝 Book page: You can read it, but can't erase words
- 💬 Text message: You can create a new message, but can't modify sent one
🐍 Python String Examples
# Different ways to create strings
name = "Python" # Double quotes
message = 'Hello World' # Single quotes
para = """This is # Triple quotes for
a multi-line string""" # multi-line text
print(type(name)) #
print(len(name)) # 6
🔑 Key Characteristics of Strings
name = "Python"
# name[0] = "J" # ❌ TypeError: 'str' object does not support item assignment
# Any "change" creates a NEW string
new_name = "J" + name[1:] # Creates new string
print(name) # Python (original unchanged)
print(new_name) # Jython (new string)
# Strings are immutable for security and performance
word = "HELLO"
# Characters have positions (0-based indexing)
print(word[0]) # H
print(word[1]) # E
print(word[4]) # O
# Order matters!
print("hello" == "olleh") # False
# Letters, numbers, symbols, spaces, emojis!
text1 = "Hello World! 123"
text2 = "Special symbols: @#$%^&*()"
text3 = "Emojis work too! 🐍🔥🎉"
text4 = "Unicode: 你好, नमस्ते, привет"
print(text3) # Emojis work too! 🐍🔥🎉
word = "PYTHON"
# Index: 0 1 2 3 4 5
# P Y T H O N
print(f"First char: {word[0]}") # P
print(f"Last char: {word[5]}") # N
print(f"Last char: {word[-1]}") # N (negative indexing)
# IndexError if out of range
# print(word[10]) # ❌ IndexError
message = "Hello"
# Loop through characters
for char in message:
print(char, end=" ") # H e l l o
# Convert to list of characters
chars = list(message)
print(chars) # ['H', 'e', 'l', 'l', 'o']
text = "Python Programming"
# Extract substrings
print(text[0:6]) # Python
print(text[7:]) # Programming
print(text[:6]) # Python
print(text[::-1]) # Reverse: gnimmargorP nohtyP
1️⃣ Single Quotes ''
name = 'Amit'
message = 'Hello, World!'
special = 'This has "double quotes" inside' # Works fine
print(name) # Amit
2️⃣ Double Quotes ""
name = "Amit"
message = "Hello, World!"
special = "This has 'single quotes' inside" # Works fine
# Use when string contains single quotes
text = "It's a beautiful day" # Easier than escaping
3️⃣ Triple Quotes (Multi-line)
# Single triple quotes
para = '''This is a
multi-line string
that spans multiple lines'''
# Double triple quotes
message = """Dear User,
Thank you for using our service.
We appreciate your feedback.
Best regards,
Team Python"""
print(para)
4️⃣ Using str() Constructor
# Convert other types to string
num_str = str(123)
print(num_str) # "123"
print(type(num_str)) #
float_str = str(3.14) # "3.14"
bool_str = str(True) # "True"
list_str = str([1,2,3]) # "[1, 2, 3]"
none_str = str(None) # "None"
# Empty string
empty = str() # ""
5️⃣ Using String Concatenation
first = "Python"
last = "Programming"
full = first + " " + last
print(full) # Python Programming
# With repetition
line = "-" * 50
print(line) # 50 dashes
# Combining different types (need str())
age = 25
message = "I am " + str(age) + " years old"
6️⃣ Using join() Method
# Join list of strings
words = ["Python", "is", "awesome"]
sentence = " ".join(words)
print(sentence) # Python is awesome
# Join with different separator
csv = ",".join(["a", "b", "c"]) # "a,b,c"
path = "/".join(["home", "user", "docs"]) # "home/user/docs"
7️⃣ Using format() and f-strings
# f-strings (Python 3.6+)
name = "Amit"
age = 25
text = f"My name is {name} and I'm {age}"
print(text) # My name is Amit and I'm 25
# format() method
text = "My name is {} and I'm {}".format(name, age)
# Template literals
template = "Hello, %s!" % name # Old style
8️⃣ Raw Strings (for paths/regex)
# Raw strings ignore escape sequences
normal = "C:\new\folder" # \n becomes newline!
raw = r"C:\new\folder" # Raw string - keeps backslashes
print(normal) # C:ewfolder (weird!)
print(raw) # C:\new\folder (correct)
# Useful for regular expressions
import re
pattern = r"\d+" # Raw string for regex
9️⃣ Bytes and Unicode
# Unicode strings (default in Python 3)
text = "Hello 你好 नमस्ते"
print(text)
# Bytes (for binary data)
bytes_data = b"Hello"
print(type(bytes_data)) #
# Convert between bytes and str
text = "Hello"
bytes_text = text.encode('utf-8')
decoded = bytes_text.decode('utf-8')
📏 String Length
text = "Hello World"
print(len(text)) # 11 (space counts)
# Empty string check
empty = ""
if len(empty) == 0:
print("String is empty")
# Or simply:
if not empty: # Empty strings are falsy
print("String is empty")
🔍 Membership Testing
text = "Python Programming"
print("Python" in text) # True
print("Java" in text) # False
print("python" in text) # False (case-sensitive)
# Case-insensitive check
if "python" in text.lower():
print("Found Python!")
# Check if string starts/ends with
print(text.startswith("Py")) # True
print(text.endswith("ing")) # True
🔢 Counting Characters
text = "hello world hello"
# Count occurrences
print(text.count("hello")) # 2
print(text.count("l")) # 5
print(text.count("z")) # 0
# Count with start/end positions
print(text.count("o", 5, 10)) # Count 'o' between indices 5-10
📊 Min/Max Characters
text = "HelloWorld"
# Based on ASCII/Unicode values
print(min(text)) # H (smallest ASCII value)
print(max(text)) # r (largest ASCII value)
# Works with lowercase/uppercase
print(min("abcABC")) # A (uppercase comes before lowercase)
🛠️ 10.2 Complete String Methods Reference
Python strings come with a rich set of built-in methods. Here's every important method with examples:
| Category | Method | Description | Example | Result |
|---|---|---|---|---|
| Case Conversion | upper() | Convert to uppercase | "hello".upper() | "HELLO" |
lower() | Convert to lowercase | "HELLO".lower() | "hello" | |
title() | Title case | "hello world".title() | "Hello World" | |
capitalize() | First letter uppercase | "python".capitalize() | "Python" | |
| Whitespace | strip() | Remove whitespace both ends | " hi ".strip() | "hi" |
lstrip() | Remove left whitespace | " hi".lstrip() | "hi" | |
rstrip() | Remove right whitespace | "hi ".rstrip() | "hi" | |
center() | Center string with padding | "hi".center(7,'*') | "**hi***" | |
| Search & Replace | find() | Find first occurrence | "hello".find("l") | 2 |
rfind() | Find from right | "hello".rfind("l") | 3 | |
index() | Like find() but raises error | "hello".index("e") | 1 | |
count() | Count occurrences | "hello".count("l") | 2 | |
replace() | Replace substring | "hi hi".replace("hi","hello") | "hello hello" | |
| Split & Join | split() | Split into list | "a,b,c".split(",") | ['a','b','c'] |
rsplit() | Split from right | "a,b,c".rsplit(",",1) | ['a,b','c'] | |
splitlines() | Split at line breaks | "a\nb".splitlines() | ['a','b'] | |
join() | Join list of strings | "-".join(['a','b']) | "a-b" | |
| Validation | isalpha() | All letters? | "abc".isalpha() | True |
isdigit() | All digits? | "123".isdigit() | True | |
isalnum() | Letters/digits only? | "abc123".isalnum() | True | |
isspace() | All whitespace? | " ".isspace() | True | |
isupper() | All uppercase? | "ABC".isupper() | True | |
islower() | All lowercase? | "abc".islower() | True | |
istitle() | Title case? | "Hello World".istitle() | True | |
| Padding & Alignment | ljust() | Left justify | "hi".ljust(5,'*') | "hi***" |
rjust() | Right justify | "hi".rjust(5,'*') | "***hi" | |
center() | Center align | "hi".center(5,'*') | "*hi**" | |
zfill() | Pad with zeros | "42".zfill(5) | "00042" | |
| Prefix/Suffix | startswith() | Check prefix | "Python".startswith("Py") | True |
endswith() | Check suffix | "Python".endswith("on") | True | |
removeprefix() | Remove prefix (3.9+) | "TestHello".removeprefix("Test") | "Hello" |
📝 Detailed Examples for Each Category
🔤 Case Conversion
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
🧹 Whitespace Methods
text = " hello world "
print(f"'{text.strip()}'") # 'hello world'
print(f"'{text.lstrip()}'") # 'hello world '
print(f"'{text.rstrip()}'") # ' hello world'
# Center and padding
print("hello".center(11, '*')) # ***hello***
print("42".zfill(5)) # 00042
🔍 Search & Replace
text = "hello world hello"
print(text.find("hello")) # 0
print(text.rfind("hello")) # 12
print(text.index("world")) # 6
print(text.count("hello")) # 2
print(text.replace("hello", "hi")) # "hi world hi"
# Replace with count
print(text.replace("hello", "hi", 1)) # "hi world hello"
✂️ Split & Join
# Split
data = "a,b,c,d"
print(data.split(",")) # ['a','b','c','d']
print(data.split(",", 2)) # ['a','b','c,d']
# Join
words = ["Python", "is", "awesome"]
print(" ".join(words)) # "Python is awesome"
print("-".join(words)) # "Python-is-awesome"
✅ Validation Methods
# Check content type
print("abc123".isalnum()) # True
print("abc123".isalpha()) # False
print("123".isdigit()) # True
print(" ".isspace()) # True
print("Hello".isupper()) # False
print("HELLO".isupper()) # True
# Practical: input validation
user_input = "25"
if user_input.isdigit():
number = int(user_input)
print(f"Valid number: {number}")
🚦 Prefix/Suffix
filename = "document.pdf"
if filename.endswith(".pdf"):
print("This is a PDF file")
if filename.startswith("doc"):
print("Document starts with 'doc'")
# Python 3.9+ removeprefix/removesuffix
text = "TestHello"
print(text.removeprefix("Test")) # "Hello"
print(text.removesuffix("lo")) # "TestHel"
✂️ 10.3 String Slicing – Complete Guide
String slicing extracts a portion (substring) from a string. Syntax: string[start:stop:step]
| Parameter | Description | Default |
|---|---|---|
start | Starting index (inclusive) | 0 |
stop | Ending index (exclusive) | end of string |
step | Increment (can be negative) | 1 |
📊 Visual Index Map
String: P Y T H O N
Index: 0 1 2 3 4 5
Negative:-6 -5 -4 -3 -2 -1
✅ Basic Slicing
text = "PYTHON PROGRAMMING"
# From index 0 to 5
print(text[0:6]) # PYTHON
# From start to index 6
print(text[:6]) # PYTHON
# From index 7 to end
print(text[7:]) # PROGRAMMING
# Complete string (copy)
print(text[:]) # PYTHON PROGRAMMING
✅ Negative Indexing
text = "PYTHON PROGRAMMING"
# Last 6 characters
print(text[-6:]) # AMMING
# Characters from -12 to -6
print(text[-12:-6]) # PROGRAM
# All except last 8
print(text[:-8]) # PYTHON PR
# First character using negative
print(text[-18]) # P
✅ Using Step
text = "PYTHON"
# Every 2nd character
print(text[::2]) # PTO
# Every 2nd from index 1
print(text[1::2]) # YHN
# With start and stop
print(text[1:5:2]) # YH
✅ Negative Step (Reverse)
text = "PYTHON"
# Reverse string
print(text[::-1]) # NOHTYP
# Reverse with step 2
print(text[::-2]) # NHP
# Reverse slice
print(text[4:1:-1]) # OHT
🎯 Practical Slicing Applications
# 1. Get first n characters
def first_n(text, n):
return text[:n]
print(first_n("Python", 3)) # Pyt
# 2. Get last n characters
def last_n(text, n):
return text[-n:] if n <= len(text) else text
print(last_n("Python", 3)) # hon
# 3. Reverse a string
def reverse_string(text):
return text[::-1]
print(reverse_string("Hello")) # olleH
# 4. Check palindrome
def is_palindrome(text):
text = text.lower().replace(" ", "")
return text == text[::-1]
print(is_palindrome("racecar")) # True
print(is_palindrome("hello")) # False
# 5. Extract domain from email
email = "user@gmail.com"
domain = email[email.index('@')+1:]
print(domain) # gmail.com
# 6. Get every other character
text = "abcdefgh"
print(text[::2]) # aceg
# 7. Remove first and last character
text = "Hello World"
print(text[1:-1]) # ello Worl
# 8. Get middle character(s)
def get_middle(text):
mid = len(text) // 2
if len(text) % 2 == 0:
return text[mid-1:mid+1]
return text[mid]
print(get_middle("Python")) # th
print(get_middle("Hello")) # l
🎨 10.4 String Formatting – The Complete Guide
1️⃣ f-strings (Python 3.6+) – RECOMMENDED
name = "Amit"
age = 25
score = 85.5
# Basic f-string
print(f"Name: {name}, Age: {age}, Score: {score}")
# Expressions inside {}
print(f"Next year you'll be {age + 1} years old")
print(f"Score in integer: {int(score)}")
# Formatting numbers
pi = 3.14159
print(f"Pi to 2 decimals: {pi:.2f}")
print(f"Pi to 3 decimals: {pi:.3f}")
# Padding and alignment
print(f"|{name:<10}|") # Left align (10 width)
print(f"|{name:>10}|") # Right align
print(f"|{name:^10}|") # Center
# With dictionary
person = {"name": "Neha", "age": 22}
print(f"Name: {person['name']}, Age: {person['age']}")
# Multi-line f-strings
message = (
f"Name: {name}\n"
f"Age: {age}\n"
f"Score: {score}"
)
print(message)
# Debugging shortcut (3.8+)
x = 10
print(f"{x = }") # x = 10
2️⃣ format() Method
# Positional arguments
print("Name: {}, Age: {}".format(name, age))
# Indexed arguments
print("Name: {0}, Age: {1}, Again: {0}".format(name, age))
# Named arguments
print("Name: {n}, Age: {a}".format(n=name, a=age))
# Format specifiers
print("Pi: {:.2f}".format(3.14159))
print("{:<10} {:>10}".format("left", "right"))
# With lists
data = ["Amit", 25, "Delhi"]
print("Name: {0[0]}, City: {0[2]}".format(data))
# With dictionaries
info = {"name": "Amit", "age": 25}
print("Name: {name}, Age: {age}".format(**info))
3️⃣ %-formatting (Old Style)
# %s for string, %d for integer, %f for float
print("Name: %s, Age: %d" % (name, age))
# With formatting
print("Pi: %.2f" % 3.14159)
# Multiple placeholders
data = ("Amit", 25, 85.5)
print("Name: %s, Age: %d, Score: %.1f" % data)
# Dictionary-style
print("Name: %(name)s, Age: %(age)d" % {"name": "Amit", "age": 25})
4️⃣ Template Strings (Safe for User Input)
from string import Template
t = Template('Hello $name, you are $age years old')
result = t.substitute(name="Amit", age=25)
print(result)
# Safe substitute (ignores missing)
t = Template('Hello $name')
print(t.safe_substitute()) # Hello $name (no error)
📊 Formatting Cheat Sheet
| Format | Meaning | Example | Output |
|---|---|---|---|
:d | Integer | f"{42:d}" | 42 |
:f | Float | f"{3.14:f}" | 3.140000 |
:.2f | 2 decimal places | f"{3.14159:.2f}" | 3.14 |
:x | Hexadecimal | f"{255:x}" | ff |
:b | Binary | f"{10:b}" | 1010 |
:o | Octal | f"{10:o}" | 12 |
:e | Scientific | f"{1000:e}" | 1.000000e+03 |
:% | Percentage | f"{0.25:%}" | 25.000000% |
:<10 | Left align (10 width) | f"{'hi':<10}" | 'hi ' |
:>10 | Right align | f"{'hi':>10}" | ' hi' |
:^10 | Center align | f"{'hi':^10}" | ' hi ' |
:05d | Zero pad (5 digits) | f"{42:05d}" | 00042 |
🔧 10.5 Escape Characters & Special Sequences
Escape characters allow you to insert special characters in strings that are otherwise difficult to type.
| Escape Sequence | Meaning | Example | Output |
|---|---|---|---|
\n | New line | "Hello\nWorld" | Hello World |
\t | Tab | "Hello\tWorld" | Hello World |
\\ | Backslash | "C:\\Users\\Name" | C:\Users\Name |
\' | Single quote | 'It\'s Python' | It's Python |
\" | Double quote | "She said \"Hello\"" | She said "Hello" |
\r | Carriage return | "Hello\rWorld" | World |
\b | Backspace | "Hello\bWorld" | HellWorld |
\f | Form feed | "Hello\fWorld" | Hello♀World |
\v | Vertical tab | "Hello\vWorld" | Hello♂World |
\a | Bell (ASCII 7) | "Hello\aWorld" | Hello♡World |
\xhh | Hex value | "\x48\x69" | Hi |
\ooo | Octal value | "\110\151" | Hi |
\N{name} | Unicode name | "\N{COPYRIGHT SIGN}" | © |
\uXXXX | 16-bit Unicode | "\u03A9" | Ω |
\UXXXXXXXX | 32-bit Unicode | "\U0001F600" | 😀 |
📝 Practical Examples
File Paths (Windows)
# Wrong (without escaping)
# path = "C:\new\folder\text.txt" # \n becomes newline!
# Correct ways
path1 = "C:\\new\\folder\\text.txt"
path2 = r"C:\new\folder\text.txt" # Raw string
print(path1) # C:\new\folder\text.txt
print(path2) # C:\new\folder\text.txt
Quotes Inside Strings
# Using escape
text1 = "She said, \"Python is awesome!\""
print(text1) # She said, "Python is awesome!"
# Using different quotes
text2 = 'She said, "Python is awesome!"'
text3 = "It's a beautiful day"
print(text2)
print(text3)
Multi-line Strings
# Using \n
address = "123 Main St\nNew York, NY\nUSA"
print(address)
# 123 Main St
# New York, NY
# USA
# Triple quotes are often better for multi-line
address2 = """123 Main St
New York, NY
USA"""
print(address2)
Unicode and Emojis
# Unicode escapes
print("\u03A9") # Ω (Omega)
print("\u00A9") # © (Copyright)
print("\U0001F600") # 😀 (Grinning face)
print("\U0001F44D") # 👍 (Thumbs up)
# Using Unicode names
print("\N{GREEK CAPITAL LETTER OMEGA}") # Ω
print("\N{COPYRIGHT SIGN}") # ©
# Emojis directly (Python 3 supports)
print("Python is awesome! 🐍🔥")
Raw Strings (r'')
# Raw strings ignore escape sequences
normal = "C:\new" # \n becomes newline
raw = r"C:\new" # Keeps backslash
print(normal) # C:ew
print(raw) # C:\new
# Useful for regex
import re
pattern = r"\d+\.\d+" # Raw string for regex
text = "Price: 10.99"
match = re.search(pattern, text)
print(match.group()) # 10.99
Formatted Output
# Creating tables with tabs
print("Name\tAge\tCity")
print("Amit\t25\tDelhi")
print("Neha\t22\tMumbai")
# Output:
# Name Age City
# Amit 25 Delhi
# Neha 22 Mumbai
# Progress bar simulation
import time
for i in range(1, 6):
print(f"\rProgress: {'█' * i}{'░' * (5-i)} {i*20}%", end="")
time.sleep(0.5)
print() # New line after progress
r"path") to avoid issues.
✅ Efficient String Concatenation
import time
# SLOW WAY (creates many intermediate strings)
start = time.time()
result = ""
for i in range(10000):
result += str(i)
slow_time = time.time() - start
# FAST WAY (using join)
start = time.time()
parts = [str(i) for i in range(10000)]
result = "".join(parts)
fast_time = time.time() - start
print(f"Slow way: {slow_time:.4f}s")
print(f"Fast way: {fast_time:.4f}s") # Much faster!
⚡ String Building Best Practices
# DO: Use join() for multiple strings
words = ["Hello", "World", "from", "Python"]
sentence = " ".join(words)
# DO: Use f-strings for formatting
name = "Amit"
message = f"Hello, {name}"
# DON'T: Use + for many strings
# bad = "Hello" + " " + "World" + " " + "from" # Slow
# DO: Use list comprehension for transformations
text = "hello world"
upper_chars = [c.upper() for c in text if c != ' ']
result = "".join(upper_chars) # HELLOWORLD
What is the output of "Python"[::-1]?
How to convert "hello" to "HELLO"?
What does " hi ".strip() return?
How to check if string contains only digits?
🏆 Challenge Problems
# Challenge 1: Count vowels in a string
def count_vowels(text):
return sum(1 for char in text.lower() if char in 'aeiou')
print(count_vowels("Hello World")) # 3
# Challenge 2: Check if string is palindrome (ignoring case and spaces)
def is_palindrome(text):
clean = ''.join(c.lower() for c in text if c.isalnum())
return clean == clean[::-1]
print(is_palindrome("A man a plan a canal Panama")) # True
# Challenge 3: Extract all email domains
def extract_domains(emails):
return [email.split('@')[1] for email in emails]
emails = ["user@gmail.com", "admin@company.com"]
print(extract_domains(emails)) # ['gmail.com', 'company.com']
# Challenge 4: Caesar cipher encryption
def caesar_cipher(text, shift):
result = []
for char in text:
if char.isalpha():
start = ord('a') if char.islower() else ord('A')
shifted = (ord(char) - start + shift) % 26 + start
result.append(chr(shifted))
else:
result.append(char)
return ''.join(result)
print(caesar_cipher("Hello", 3)) # Khoor
🎓 Module 10 : String (Working with Text) Successfully Completed
You have successfully completed this module of Python for Cybersecurity.
Keep building your expertise step by step — Learn Next Module →
📘 Python Lists – The Complete Master Guide
A List in Python is an ordered, mutable (changeable) collection that can store multiple items in a single variable. Think of it as a dynamic container that can hold anything — numbers, strings, booleans, even other lists! Lists are one of the most versatile and commonly used data structures in Python.
🔑 Key Properties:
- Ordered: Items maintain the order you add them
- Mutable: Can change, add, remove items after creation
- Heterogeneous: Can store different data types together
- Dynamic: Grows and shrinks as needed (no fixed size)
- Indexable: Access items by position (0-based indexing)
🍎 11.1 What is a List? – The Ultimate Deep Dive
A list in Python is a powerful, flexible, and versatile data structure that serves as a dynamic array capable of storing multiple items in a single variable. Think of it as a smart container that can hold anything — numbers, text, boolean values, or even other lists!
📌 Core Definition
A list is an ordered, mutable (changeable), and heterogeneous collection that allows duplicate items and can grow or shrink dynamically.
🎯 Real-World Analogy
Lists are like a shopping list on a fridge – you can add items, remove items, change items, and the order matters. You can even have a list within a list (like categories).
Lists can be created using various methods. Each method has its own use case and advantages. Here's every possible way with detailed explanations:
📦 Method 1: Square Brackets [ ] – Most Common
The simplest and most intuitive way to create lists.
# List of strings (fruits)
fruits = ["apple", "banana", "mango", "orange", "grape"]
# List of integers (numbers)
numbers = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
# Mixed data types – Python's flexibility shines!
mixed = ["John", 25, True, 12.5, None, 3.14, False, "Python"]
# Empty list – starting point for dynamic data
empty = []
# Nested lists – lists within lists
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
# List with repeated values using multiplication
zeros = [0] * 10 # Creates [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
✅ Advantages:
- Most readable
- Fastest execution
- Supports all types
- Can create nested structures
📦 Method 2: list() Constructor – Converting Iterables
Convert any iterable (string, tuple, range, set, dictionary) into a list.
# From string – each character becomes an element
chars = list("hello world")
# Result: ['h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd']
# From tuple
numbers = list((1, 2, 3, 4, 5, 6, 7, 8, 9, 10))
# Result: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# From range – very useful for generating sequences
range_list = list(range(1, 21, 2)) # Odd numbers from 1 to 19
# Result: [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
# From set – order may vary (sets are unordered)
set_list = list({10, 20, 30, 40, 50})
# Result: [40, 10, 50, 20, 30] (order not guaranteed)
# From dictionary keys
dict_keys = list({"name": "John", "age": 30, "city": "NYC"})
# Result: ['name', 'age', 'city']
# From dictionary values
dict_values = list({"name": "John", "age": 30, "city": "NYC"}.values())
# Result: ['John', 30, 'NYC']
# Empty list using constructor
empty = list() # []
✅ Best For:
- Converting other types
- Creating from ranges
- Dynamic list generation
📦 Method 3: List Comprehension – Pythonic & Powerful
Create lists using concise, readable expressions. 2-3x faster than traditional loops.
# Basic comprehension: squares of numbers
squares = [x**2 for x in range(1, 11)]
# Result: [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
# With condition: even numbers only
evens = [x for x in range(1, 21) if x % 2 == 0]
# Result: [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
# With if-else: categorize numbers
categories = ["even" if x % 2 == 0 else "odd" for x in range(1, 11)]
# Result: ['odd', 'even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd', 'even']
# Nested comprehension: flatten matrix
matrix = [[1, 2], [3, 4], [5, 6]]
flattened = [num for row in matrix for num in row]
# Result: [1, 2, 3, 4, 5, 6]
# Cartesian product
colors = ["red", "blue"]
sizes = ["S", "M", "L"]
products = [(color, size) for color in colors for size in sizes]
# Result: [('red','S'), ('red','M'), ('red','L'), ('blue','S'), ('blue','M'), ('blue','L')]
# String manipulation
words = ["hello", "world", "python"]
upper_words = [word.upper() for word in words]
# Result: ['HELLO', 'WORLD', 'PYTHON']
# Complex transformation
numbers = [1, 2, 3, 4, 5]
transformed = [x*2 if x % 2 == 0 else x*3 for x in numbers]
# Result: [3, 4, 9, 8, 15]
⚡ Advantages:
- 2-3x faster than loops
- More readable
- Memory efficient
- Functional programming style
📦 Method 4: split() – From Strings
Perfect for parsing text data, CSV files, and user input.
# Split by whitespace (default)
sentence = "Python is an amazing programming language"
words = sentence.split()
# Result: ['Python', 'is', 'an', 'amazing', 'programming', 'language']
# Split by comma (CSV data)
csv_data = "apple,banana,mango,orange,grape,kiwi"
fruits = csv_data.split(",")
# Result: ['apple', 'banana', 'mango', 'orange', 'grape', 'kiwi']
# Split by custom delimiter
data = "2023-12-25|John Doe|5000|Approved"
fields = data.split("|")
# Result: ['2023-12-25', 'John Doe', '5000', 'Approved']
# Split with maxsplit parameter
text = "one two three four five"
first_three = text.split(" ", 3) # Split only first 3 spaces
# Result: ['one', 'two', 'three', 'four five']
# Split lines from multi-line text
multiline = """Line 1
Line 2
Line 3
Line 4"""
lines = multiline.split("\n")
# Result: ['Line 1', 'Line 2', 'Line 3', 'Line 4']
📊 Use Cases:
- Parsing CSV files
- Processing user input
- Text analysis
- Log file parsing
📦 Method 5: Advanced Techniques & Special Cases
# 1. Using * operator for repetition
pattern = [1, 2, 3] * 4
# Result: [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
# 2. From user input (with error handling)
user_input = input("Enter numbers separated by spaces: ")
try:
numbers = [int(x) for x in user_input.split()]
except ValueError:
print("Invalid input!")
# 3. Using map() function
numbers = list(map(int, ["1", "2", "3", "4", "5"]))
# Result: [1, 2, 3, 4, 5]
# 4. Using filter() function
numbers = list(range(1, 21))
evens = list(filter(lambda x: x % 2 == 0, numbers))
# Result: [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
# 5. Using itertools (for advanced combinations)
import itertools
letters = ['a', 'b', 'c']
combinations = list(itertools.combinations(letters, 2))
# Result: [('a', 'b'), ('a', 'c'), ('b', 'c')]
# 6. From generator expression
squares_gen = (x**2 for x in range(10)) # Generator
squares_list = list(squares_gen) # Convert to list
# Result: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
# 7. Creating 2D lists properly
# WRONG WAY (creates references):
wrong = [[0] * 3] * 3 # [[0,0,0], [0,0,0], [0,0,0]]
wrong[0][0] = 5 # Changes all rows!
# CORRECT WAY:
correct = [[0] * 3 for _ in range(3)] # Independent rows
correct[0][0] = 5 # Only first row changes
fruits = ["🍎apple", "🍌banana", "🥭mango", "🍊orange", "🍇grapes"]
│ │ │ │ │
Positive: 0 1 2 3 4
Negative: -5 -4 -3 -2 -1
fruits = ["🍎apple", "🍌banana", "🥭mango", "🍊orange", "🍇grapes"]
# Accessing individual elements
print(f"First fruit: {fruits[0]}") # 🍎apple
print(f"Third fruit: {fruits[2]}") # 🥭mango
print(f"Last fruit: {fruits[4]}") # 🍇grapes
# Accessing in expressions
index = 3
print(f"Fruit at index {index}: {fruits[index]}") # 🍊orange
# Modifying elements using index
fruits[1] = "🍒cherry" # Change banana to cherry
print(fruits) # ['🍎apple', '🍒cherry', '🥭mango', '🍊orange', '🍇grapes']
# Common pattern: accessing with variable
for i in range(len(fruits)):
print(f"Position {i}: {fruits[i]}")
# Important: IndexError demonstration
try:
print(fruits[10]) # This index doesn't exist
except IndexError as e:
print(f"Error: {e} - List has only {len(fruits)} elements")
fruits = ["🍎apple", "🍌banana", "🥭mango", "🍊orange", "🍇grapes"]
# Negative indices count from the end
print(f"Last item: {fruits[-1]}") # 🍇grapes
print(f"Second last: {fruits[-2]}") # 🍊orange
print(f"First item: {fruits[-5]}") # 🍎apple
# Practical use cases
def get_last_n_items(lst, n):
"""Get last n items from list"""
return lst[-n:] if n <= len(lst) else lst
print(get_last_n_items(fruits, 3)) # ['🥭mango', '🍊orange', '🍇grapes']
# Mixing positive and negative in expressions
middle_items = fruits[1:-1] # All except first and last
print(middle_items) # ['🍌banana', '🥭mango', '🍊orange']
# Negative indexing with modification
fruits[-2] = "🍍pineapple" # Change second last item
print(fruits) # ['🍎apple', '🍌banana', '🥭mango', '🍍pineapple', '🍇grapes']
# Special case: -0 is same as 0
print(fruits[-0]) # 🍎apple (same as fruits[0])
🎯 Index Calculation Rules
# Relationship between positive and negative indices
# negative_index = positive_index - length
fruits = ['a', 'b', 'c', 'd', 'e']
length = len(fruits) # 5
# For last element:
# positive: 4
# negative: 4 - 5 = -1 ✅
# For first element:
# positive: 0
# negative: 0 - 5 = -5 ✅
# Quick conversion function
def to_negative_index(lst, pos_index):
return pos_index - len(lst)
print(to_negative_index(fruits, 3)) # -2 (which is 'd')
⚠️ Common Indexing Pitfalls
# 1. Off-by-one errors
fruits = ['a', 'b', 'c']
# WRONG:
# for i in range(1, len(fruits)): # Misses first element
# print(fruits[i])
# CORRECT:
for i in range(len(fruits)):
print(fruits[i])
# 2. Index out of range
try:
print(fruits[10])
except IndexError:
print("Always check length first!")
# 3. Negative index confusion
# -0 is not negative, it's 0
print(fruits[-0]) # 'a', not last element!
# 4. Empty list indexing
empty = []
# print(empty[0]) # IndexError
# print(empty[-1]) # IndexError
# Safe access function
def safe_access(lst, index):
try:
return lst[index]
except IndexError:
return None
Indexing Cheat Sheet
| Operation | Code | Result (for list [10,20,30,40,50]) |
|---|---|---|
| First element | list[0] | 10 |
| Last element | list[-1] | 50 |
| Second element | list[1] | 20 |
| Second last | list[-2] | 40 |
| Middle element | list[len(list)//2] | 30 |
| Safe access | list[index] if 0 <= index < len(list) else None | - |
Lists maintain the exact order in which items are inserted. This order is preserved throughout the list's lifetime.
# Order matters!
list1 = [1, 2, 3, 4]
list2 = [4, 3, 2, 1]
print(list1 == list2) # False
# Order preserved through operations
fruits = []
fruits.append("banana")
fruits.append("apple")
fruits.append("cherry")
print(fruits) # ['banana', 'apple', 'cherry']
Unlike strings and tuples, lists can be modified after creation. This includes changing, adding, or removing elements.
fruits = ["apple", "banana"]
# Change existing item
fruits[0] = "mango"
print(fruits) # ['mango', 'banana']
# Add new item
fruits.append("orange")
print(fruits) # ['mango', 'banana', 'orange']
# Remove item
fruits.remove("banana")
print(fruits) # ['mango', 'orange']
Lists can store any data type together: integers, floats, strings, booleans, None, other lists, and even custom objects.
mixed = [
"John", # string
25, # integer
3.14, # float
True, # boolean
None, # NoneType
[1, 2, 3], # nested list
{"name": "Jane"}, # dictionary
(4, 5, 6) # tuple
]
print(f"String: {mixed[0]}")
print(f"Integer: {mixed[1]}")
print(f"Float: {mixed[2]}")
print(f"Boolean: {mixed[3]}")
print(f"None: {mixed[4]}")
print(f"Nested list: {mixed[5]}")
print(f"Dictionary: {mixed[6]}")
print(f"Tuple: {mixed[7]}")
Lists automatically grow and shrink as needed. No need to pre-allocate size like in other languages.
# Start empty
items = []
print(f"Size: {len(items)}") # 0
# Add items – automatically grows
items.append(1)
items.append(2)
items.append(3)
print(f"Size: {len(items)}") # 3
print(items) # [1, 2, 3]
# Remove items – automatically shrinks
items.pop()
print(f"Size: {len(items)}") # 2
print(items) # [1, 2]
# Lists can hold millions of items
big_list = list(range(1_000_000))
print(f"Big list size: {len(big_list)}") # 1,000,000
Lists can contain duplicate values. This is useful for frequency counting and maintaining all occurrences.
numbers = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
print(numbers) # [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
# Count occurrences
print(f"Number of 2s: {numbers.count(2)}") # 2
print(f"Number of 3s: {numbers.count(3)}") # 3
print(f"Number of 4s: {numbers.count(4)}") # 4
# Finding all indices of duplicates
def find_all_indices(lst, value):
return [i for i, x in enumerate(lst) if x == value]
print(find_all_indices(numbers, 3)) # [3, 4, 5]
# Duplicates are preserved in operations
numbers.append(3) # Add another 3
print(numbers.count(3)) # 4 now
Lists can contain other lists, creating multi-dimensional structures like matrices, tables, and complex data hierarchies.
# 2D Matrix
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
# Accessing elements
print(matrix[0][1]) # 2 (row 0, col 1)
print(matrix[2][2]) # 9 (row 2, col 2)
# 3D structure
cube = [
[[1,2], [3,4]],
[[5,6], [7,8]],
[[9,10], [11,12]]
]
print(cube[1][0][1]) # 6
# Jagged lists (uneven rows)
jagged = [
[1, 2],
[3, 4, 5],
[6],
[7, 8, 9, 10]
]
Lists support both indexing (access single element) and slicing (access sublist).
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# Indexing (single element)
print(numbers[5]) # 5
print(numbers[-3]) # 7
# Slicing (sublist)
print(numbers[2:5]) # [2, 3, 4]
print(numbers[:4]) # [0, 1, 2, 3]
print(numbers[6:]) # [6, 7, 8, 9]
print(numbers[::2]) # [0, 2, 4, 6, 8]
print(numbers[::-1]) # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
Lists can be iterated over in loops, comprehensions, and with various iteration tools.
fruits = ["apple", "banana", "cherry"]
# For loop
for fruit in fruits:
print(fruit.upper())
# While loop with index
i = 0
while i < len(fruits):
print(f"{i}: {fruits[i]}")
i += 1
# Enumerate
for i, fruit in enumerate(fruits):
print(f"Index {i}: {fruit}")
# Iteration tools
from itertools import cycle
for fruit, count in zip(cycle(fruits), range(5)):
print(fruit, count)
Lists are mutable, so they cannot be used as dictionary keys or set elements. Use tuples instead for hashable sequences.
# Lists cannot be dictionary keys
# my_dict = {[1,2]: "value"} # ❌ TypeError
# Lists cannot be set elements
# my_set = {[1,2], [3,4]} # ❌ TypeError
# Workaround: Convert to tuple
key = tuple([1, 2, 3])
my_dict = {key: "value"} # ✅ Works
# Check hashability
print(hash((1,2,3))) # ✅ Tuples are hashable
# print(hash([1,2,3])) # ❌ Lists are not
Lists are reference types. Assignment creates a reference, not a copy. This is crucial for understanding list behavior.
# Reference behavior
list1 = [1, 2, 3]
list2 = list1 # This is NOT a copy!
list2.append(4)
print(list1) # [1, 2, 3, 4] (original changed!)
# To actually copy:
list3 = list1.copy() # Method 1
list4 = list1[:] # Method 2
list5 = list(list1) # Method 3
list3.append(5)
print(list1) # [1, 2, 3, 4] (unchanged)
print(list3) # [1, 2, 3, 4, 5]
# Function argument behavior
def modify_list(lst):
lst.append(100)
my_list = [1, 2, 3]
modify_list(my_list)
print(my_list) # [1, 2, 3, 100] (modified!)
✅ Type Checking Methods
fruits = ["apple", "banana"]
# Method 1: type()
print(type(fruits)) #
print(type(fruits) == list) # True
# Method 2: isinstance() (recommended)
print(isinstance(fruits, list)) # True
print(isinstance("hello", list)) # False
# Method 3: checking against other types
print(isinstance(fruits, (list, tuple))) # True (list or tuple)
# Method 4: checking for sequence
from collections.abc import Sequence
print(isinstance(fruits, Sequence)) # True (lists are sequences)
When to use which:
type()– When you need exact type matchisinstance()– When checking inheritance (recommended)isinstance(x, (list, tuple))– Multiple type check
🔄 Converting Other Types to List
| Source Type | Code Example | Result | Notes |
|---|---|---|---|
| String | list("hello") |
['h','e','l','l','o'] |
Each character becomes element |
| Tuple | list((1,2,3)) |
[1,2,3] |
Preserves order |
| Set | list({1,2,3}) |
[1,2,3] (order may vary) |
Order not guaranteed |
| Range | list(range(5)) |
[0,1,2,3,4] |
Very memory efficient |
| Dictionary (keys) | list({"a":1, "b":2}) |
['a','b'] |
Keys become elements |
| Dictionary (values) | list({"a":1, "b":2}.values()) |
[1,2] |
Values become elements |
| Dictionary (items) | list({"a":1, "b":2}.items()) |
[('a',1), ('b',2)] |
Tuples of key-value pairs |
| Generator | list(x**2 for x in range(5)) |
[0,1,4,9,16] |
Materializes generator |
| Map object | list(map(str, [1,2,3])) |
['1','2','3'] |
Convert map to list |
| Filter object | list(filter(lambda x: x%2==0, range(10))) |
[0,2,4,6,8] |
Convert filter to list |
🔄 Converting List to Other Types
| Target Type | Code Example | Result | Notes |
|---|---|---|---|
| Tuple | tuple([1,2,3]) |
(1,2,3) |
Creates immutable version |
| Set | set([1,2,2,3]) |
{1,2,3} |
Removes duplicates |
| String (join) | "".join(['h','e','l','l','o']) |
"hello" |
Elements must be strings |
| String (with separator) | ", ".join(["a","b","c"]) |
"a, b, c" |
Custom separator |
| Dictionary (from pairs) | dict([('a',1), ('b',2)]) |
{'a':1, 'b':2} |
List of 2-element tuples |
| Dictionary (enumerate) | dict(enumerate(['a','b','c'])) |
{0:'a', 1:'b', 2:'c'} |
Index becomes key |
🎯 Advanced Conversion Examples
# 1. List of strings to single string
words = ["Python", "is", "awesome"]
sentence = " ".join(words)
print(sentence) # "Python is awesome"
# 2. List of numbers to list of strings
numbers = [1, 2, 3, 4, 5]
str_numbers = [str(n) for n in numbers]
print(str_numbers) # ['1', '2', '3', '4', '5']
# 3. List of pairs to dictionary
pairs = [("name", "John"), ("age", 30), ("city", "NYC")]
person = dict(pairs)
print(person) # {'name': 'John', 'age': 30, 'city': 'NYC'}
# 4. List to CSV string
data = ["John", "Doe", 30, "Engineer"]
csv = ",".join(str(item) for item in data)
print(csv) # "John,Doe,30,Engineer"
# 5. Nested list to flat list (flatten)
nested = [[1,2], [3,4], [5,6]]
flat = [num for sublist in nested for num in sublist]
print(flat) # [1, 2, 3, 4, 5, 6]
# 6. List to dictionary with default values
keys = ["name", "age", "city"]
default_dict = dict.fromkeys(keys, "unknown")
print(default_dict) # {'name': 'unknown', 'age': 'unknown', 'city': 'unknown'}
📐 Length Operations
fruits = ["apple", "banana", "mango", "orange", "grape"]
# Basic length
print(len(fruits)) # 5
# Length in conditions
if len(fruits) > 0:
print(f"List has {len(fruits)} items")
# Empty list check (Pythonic)
if not fruits: # Empty lists are falsy
print("List is empty")
else:
print(f"List has {len(fruits)} items")
# Length for loops
for i in range(len(fruits)):
print(f"{i}: {fruits[i]}")
# Length for slicing
mid = len(fruits) // 2
first_half = fruits[:mid]
second_half = fruits[mid:]
# Length for validation
def safe_get(lst, index):
if 0 <= index < len(lst):
return lst[index]
return None
🔍 Membership Testing
fruits = ["apple", "banana", "mango", "orange", "grape"]
# Basic membership
print("apple" in fruits) # True
print("kiwi" in fruits) # False
print("kiwi" not in fruits) # True
# Case sensitivity
print("Apple" in fruits) # False (case-sensitive)
# Practical examples
if "banana" in fruits:
print("Making banana smoothie!")
# Checking multiple items
required = ["apple", "banana"]
if all(item in fruits for item in required):
print("All required fruits available")
# Any of multiple items
wanted = ["kiwi", "mango", "pear"]
if any(item in fruits for item in wanted):
print("At least one wanted fruit available")
# Performance note: 'in' is O(n) for lists
# For frequent membership tests, consider using sets
🎯 Advanced Membership Techniques
# 1. Finding position of item (first occurrence)
fruits = ["apple", "banana", "mango", "banana", "orange"]
if "banana" in fruits:
pos = fruits.index("banana")
print(f"First banana at index {pos}") # 1
# 2. Finding all positions
def find_all(lst, item):
return [i for i, x in enumerate(lst) if x == item]
print(find_all(fruits, "banana")) # [1, 3]
# 3. Counting occurrences
print(fruits.count("banana")) # 2
print(fruits.count("apple")) # 1
# 4. Checking if any item meets condition
numbers = [1, 3, 5, 7, 8, 9]
has_even = any(x % 2 == 0 for x in numbers)
print(has_even) # True (8 is even)
# 5. Checking if all items meet condition
all_positive = all(x > 0 for x in numbers)
print(all_positive) # True
# 6. Membership with custom objects
class Person:
def __init__(self, name):
self.name = name
def __eq__(self, other):
return self.name == other.name
people = [Person("John"), Person("Jane")]
print(Person("John") in people) # True (if __eq__ defined)
Python compares lists lexicographically – element by element, from left to right.
Equality Comparison (==, !=)
list1 = [1, 2, 3]
list2 = [1, 2, 3]
list3 = [1, 2, 4]
list4 = [3, 2, 1]
print(list1 == list2) # True (same elements, same order)
print(list1 == list3) # False (last element differs)
print(list1 == list4) # False (different order)
# Works with different lengths
list5 = [1, 2]
print(list1 == list5) # False (different lengths)
# Works with mixed types (if comparable)
print([1, "a"] == [1, "a"]) # True
Ordering Comparisons (<, >, <=, >=)
# Element by element comparison
print([1, 2, 3] < [1, 2, 4]) # True (3 < 4)
print([1, 2, 3] < [1, 3]) # True (2 < 3)
print([2, 1] < [1, 2]) # False (2 > 1)
# Length considered only if all equal so far
print([1, 2] < [1, 2, 3]) # True (shorter < longer when prefix equal)
# Complex comparisons
print(["apple", "banana"] < ["apple", "cherry"]) # True (banana < cherry)
# Type compatibility
# print([1, 2] < [1, "a"]) # TypeError: '<' not supported
📊 Lexicographic Comparison Rules
- Compare first elements: if they differ, that decides the result
- If first elements equal, compare second, and so on
- If all elements equal but one list is longer, the shorter is considered smaller
- If all elements equal and same length, lists are equal
# Examples demonstrating the rules
print([1, 2, 3] < [1, 2, 4]) # Rule 1: 3 < 4 → True
print([1, 2] < [1, 2, 3]) # Rule 3: shorter < longer → True
print([1, 2, 3] < [1, 2]) # Rule 3 (reverse): longer > shorter → False
print([1, 2] == [1, 2]) # Rule 4: True
🎯 Advanced Comparison Scenarios
# 1. Comparing nested lists
print([[1,2], [3,4]] == [[1,2], [3,4]]) # True
print([[1,2], [3,4]] < [[1,2], [3,5]]) # True (4 < 5)
# 2. Using cmp_to_key for custom sorting
from functools import cmp_to_key
def custom_cmp(a, b):
# Sort by length first, then by values
if len(a) != len(b):
return len(a) - len(b)
return (a > b) - (a < b) # Standard comparison
lists = [[1,2,3], [4,5], [1], [2,3]]
sorted_lists = sorted(lists, key=cmp_to_key(custom_cmp))
print(sorted_lists) # [[1], [4,5], [2,3], [1,2,3]]
# 3. Checking if list is sorted
def is_sorted(lst):
return all(lst[i] <= lst[i+1] for i in range(len(lst)-1))
print(is_sorted([1,2,3,4])) # True
print(is_sorted([1,3,2,4])) # False
# 4. Finding min/max in list of lists
list_of_lists = [[1,2], [3,4,5], [1], [2,3,4]]
print(max(list_of_lists)) # [3,4,5] (lexicographically largest)
print(min(list_of_lists)) # [1] (smallest)
📊 Time Complexity
| Operation | Time Complexity | Notes |
|---|---|---|
Indexing lst[i] | O(1) | Constant time |
| Append | O(1) | Amortized constant |
| Pop (last) | O(1) | Constant time |
| Pop (first) | O(n) | Shifts all elements |
| Insert | O(n) | Shifts elements |
| Remove | O(n) | Search + shift |
Membership in | O(n) | Linear search |
| Sort | O(n log n) | Timsort algorithm |
💿 Memory Considerations
import sys
# Memory overhead
empty_list = []
print(f"Empty list: {sys.getsizeof(empty_list)} bytes") # ~56 bytes
# Each element adds reference (8 bytes on 64-bit)
numbers = list(range(1000))
print(f"1000 numbers: {sys.getsizeof(numbers)} bytes") # ~8,000 + overhead
# Lists store references, not objects themselves
# Multiple lists can share references
a = [1, 2, 3]
b = a # No memory allocation for new list
# Memory optimization tips
# 1. Use array module for large numeric lists
# 2. Use generator for large sequences
# 3. Use slice assignment carefully
⚡ Performance Tips
# 1. List comprehension is faster than append in loops
# SLOW:
result = []
for i in range(1000):
result.append(i**2)
# FAST:
result = [i**2 for i in range(1000)]
# 2. Pre-allocate if size known (slightly faster)
# Pre-allocate
result = [0] * 1000
for i in range(1000):
result[i] = i**2
# 3. Use deque for frequent front operations
from collections import deque
dq = deque([1,2,3])
dq.appendleft(0) # O(1) vs list's O(n)
dq.popleft() # O(1) vs list's O(n)
# 4. Membership testing: use set for repeated checks
# SLOW for many checks:
data = [1,2,3,4,5]
if 5 in data: # O(n) each time
# FAST:
data_set = set(data)
if 5 in data_set: # O(1) each time
# 5. Sort with key instead of cmp
# SLOW:
data.sort(key=lambda x: x[1]) # ✅ Good
# AVOID custom comparators unless necessary
🛠️ 11.2 Complete List Methods Reference – The Ultimate Guide
1️⃣ .append(item) – Add Single Item to End
Adds one element to the end of the list. This is the most common way to build lists dynamically.
# Basic usage
fruits = ["apple", "banana"]
fruits.append("orange")
print(fruits) # ['apple', 'banana', 'orange']
# Append works with ANY data type
mixed = []
mixed.append(42) # Integer
mixed.append(3.14) # Float
mixed.append(True) # Boolean
mixed.append("hello") # String
mixed.append([1, 2, 3]) # Nested list
mixed.append({"key": "value"}) # Dictionary
mixed.append(None) # NoneType
print(mixed)
# [42, 3.14, True, 'hello', [1, 2, 3], {'key': 'value'}, None]
# Append in loops – building lists dynamically
squares = []
for i in range(10):
squares.append(i ** 2)
print(squares) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
# Append returns None (important!)
result = fruits.append("grape")
print(result) # None (append modifies list in-place)
🎯 Key Points:
- Time Complexity: O(1) amortized
- Modifies list in-place
- Returns
None - Can append any Python object
- List grows automatically
📊 Performance:
1M appends: ~0.1 seconds
🔍 Advanced append() examples:
# Append vs. concatenation (important difference!)
list1 = [1, 2, 3]
list1.append([4, 5]) # Adds as SINGLE element
print(list1) # [1, 2, 3, [4, 5]] (nested list)
list2 = [1, 2, 3]
list2 += [4, 5] # Concatenates (extends)
print(list2) # [1, 2, 3, 4, 5] (flattened)
# Append with conditional logic
numbers = []
for i in range(20):
if i % 3 == 0: # Append multiples of 3
numbers.append(i)
print(numbers) # [0, 3, 6, 9, 12, 15, 18]
# Building matrix row by row
matrix = []
for i in range(3):
row = []
for j in range(3):
row.append(i * 3 + j + 1)
matrix.append(row)
print(matrix) # [[1,2,3], [4,5,6], [7,8,9]]
2️⃣ .insert(index, item) – Insert at Specific Position
Inserts an element at any position. Elements after the index shift right.
# Basic insertion
fruits = ["apple", "banana", "mango"]
fruits.insert(1, "orange") # Insert at index 1
print(fruits) # ['apple', 'orange', 'banana', 'mango']
# Insert at beginning (index 0)
fruits.insert(0, "grape")
print(fruits) # ['grape', 'apple', 'orange', 'banana', 'mango']
# Insert at end (same as append)
fruits.insert(len(fruits), "kiwi")
print(fruits) # ['grape', 'apple', 'orange', 'banana', 'mango', 'kiwi']
# Insert with negative indices
numbers = [10, 20, 30, 40]
numbers.insert(-1, 25) # Insert before last element
print(numbers) # [10, 20, 30, 25, 40]
numbers.insert(-2, 27) # Insert before second last
print(numbers) # [10, 20, 30, 27, 25, 40]
# Insert beyond length – appends at end
numbers.insert(100, 99) # Index too large → append
print(numbers) # [10, 20, 30, 27, 25, 40, 99]
🎯 Key Points:
- Time Complexity: O(n) (shifts elements)
- If index >= len(list), appends at end
- If index <= -len(list)-1, inserts at beginning
- Returns
None
🔍 Advanced insert() patterns:
# Insert multiple items using loop
def insert_multiple(lst, index, items):
"""Insert multiple items at specified index"""
for i, item in enumerate(items):
lst.insert(index + i, item)
fruits = ["apple", "mango"]
insert_multiple(fruits, 1, ["banana", "orange", "grape"])
print(fruits) # ['apple', 'banana', 'orange', 'grape', 'mango']
# Maintaining sorted order while inserting
def insert_sorted(lst, item):
"""Insert item maintaining sorted order (ascending)"""
for i, x in enumerate(lst):
if item < x:
lst.insert(i, item)
return
lst.append(item)
sorted_list = [10, 20, 30, 40, 50]
insert_sorted(sorted_list, 35)
print(sorted_list) # [10, 20, 30, 35, 40, 50]
# Insert at position based on condition
names = ["Alice", "Bob", "David", "Eve"]
# Insert "Charlie" after "Bob"
for i, name in enumerate(names):
if name == "Bob":
names.insert(i + 1, "Charlie")
break
print(names) # ['Alice', 'Bob', 'Charlie', 'David', 'Eve']
3️⃣ .extend(iterable) – Add Multiple Items
Adds all elements from an iterable (list, tuple, string, set, etc.) to the end.
# Extend with another list
fruits = ["apple", "banana"]
more_fruits = ["orange", "grape", "kiwi"]
fruits.extend(more_fruits)
print(fruits) # ['apple', 'banana', 'orange', 'grape', 'kiwi']
# Extend with tuple
fruits.extend(("mango", "cherry"))
print(fruits) # ['apple', 'banana', 'orange', 'grape', 'kiwi', 'mango', 'cherry']
# Extend with string (adds each character!)
fruits.extend("hello")
print(fruits) # ... 'h', 'e', 'l', 'l', 'o' added
# Extend with range
numbers = [1, 2, 3]
numbers.extend(range(4, 8))
print(numbers) # [1, 2, 3, 4, 5, 6, 7]
# Extend with set (order may vary)
numbers.extend({8, 9, 10})
print(numbers) # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
🎯 Key Points:
- Time Complexity: O(k) where k = length of iterable
- Accepts ANY iterable (list, tuple, string, range, set, dict, generator)
- Modifies list in-place
- Returns
None
🔍 extend() vs append() – CRITICAL DIFFERENCE:
# CRITICAL: append() vs extend()
list1 = [1, 2, 3]
list1.append([4, 5]) # Adds as SINGLE element
print(list1) # [1, 2, 3, [4, 5]] (length 4)
list2 = [1, 2, 3]
list2.extend([4, 5]) # Adds as MULTIPLE elements
print(list2) # [1, 2, 3, 4, 5] (length 5)
# extend() with different iterables
nums = [1, 2, 3]
nums.extend("abc") # String → adds characters
print(nums) # [1, 2, 3, 'a', 'b', 'c']
nums.extend((4, 5)) # Tuple
nums.extend({6, 7}) # Set
nums.extend(range(8, 10)) # Range
print(nums) # [1, 2, 3, 'a', 'b', 'c', 4, 5, 6, 7, 8, 9]
# extend() with generator (memory efficient)
def generate_numbers(n):
for i in range(n):
yield i ** 2
squares = [10, 20]
squares.extend(generate_numbers(5))
print(squares) # [10, 20, 0, 1, 4, 9, 16]
4️⃣ + Operator – Concatenate Lists (Creates New List)
Creates a new list by combining existing lists. Original lists remain unchanged.
# Basic concatenation
list1 = [1, 2, 3]
list2 = [4, 5, 6]
combined = list1 + list2
print(combined) # [1, 2, 3, 4, 5, 6]
print(list1) # [1, 2, 3] (unchanged)
print(list2) # [4, 5, 6] (unchanged)
# Multiple concatenation
result = [1, 2] + [3, 4] + [5, 6] + [7, 8]
print(result) # [1, 2, 3, 4, 5, 6, 7, 8]
# Mixing types (must be lists)
# result = [1, 2] + (3, 4) # ❌ TypeError: can only concatenate list (not "tuple") to list
# Concatenating empty lists
empty = [] + [1, 2, 3]
print(empty) # [1, 2, 3]
# Using + with assignment
numbers = [1, 2]
numbers = numbers + [3, 4] # Creates new list and reassigns
print(numbers) # [1, 2, 3, 4]
🎯 Key Points:
- Time Complexity: O(n + m)
- Creates NEW list (copy)
- Original lists unchanged
- Both operands must be lists
- Memory: Creates complete copy
🔍 + Operator vs extend():
# Memory comparison
import sys
list_a = [1, 2, 3]
list_b = [4, 5, 6]
# extend() – modifies in-place, no new list
list_a.extend(list_b)
print(f"extend() - same list: {sys.getsizeof(list_a)} bytes")
# + operator – creates new list
list_c = [1, 2, 3]
list_d = [4, 5, 6]
new_list = list_c + list_d
print(f"+ operator - new list: {sys.getsizeof(new_list)} bytes")
print(f"Original list_c: {sys.getsizeof(list_c)} bytes (unchanged)")
# Performance comparison
import time
# extend() - faster for large lists
start = time.time()
result = []
for i in range(100):
result.extend(range(1000))
extend_time = time.time() - start
# + operator - slower (creates many copies)
start = time.time()
result = []
for i in range(100):
result = result + list(range(1000))
concat_time = time.time() - start
print(f"extend() time: {extend_time:.4f}s")
print(f"+ operator time: {concat_time:.4f}s") # Much slower!
5️⃣ * Operator – List Repetition
Creates a new list by repeating the original list multiple times.
# Basic repetition
zeros = [0] * 5
print(zeros) # [0, 0, 0, 0, 0]
pattern = [1, 2, 3] * 3
print(pattern) # [1, 2, 3, 1, 2, 3, 1, 2, 3]
# Repetition with mixed types
mixed = ["a", True, 42] * 2
print(mixed) # ['a', True, 42, 'a', True, 42]
# Repetition with empty list
empty = [] * 5
print(empty) # [] (still empty)
# Nested list repetition - CAUTION!
nested = [[0]] * 3
print(nested) # [[0], [0], [0]]
nested[0][0] = 5
print(nested) # [[5], [5], [5]] (all elements changed! - same reference)
# Correct way for nested lists
correct = [[0] for _ in range(3)]
correct[0][0] = 5
print(correct) # [[5], [0], [0]] (independent)
🎯 Key Points:
- Time Complexity: O(n * k)
- Creates NEW list
- ⚠️ For mutable objects, repeats the SAME reference!
- Use list comprehension for independent copies
🔍 Advanced repetition patterns:
# Creating default lists
matrix = [[0] * 4 for _ in range(3)] # 3x4 matrix
print(matrix) # [[0,0,0,0], [0,0,0,0], [0,0,0,0]]
# Creating patterns
pattern = [1, 0] * 5
print(pattern) # [1, 0, 1, 0, 1, 0, 1, 0, 1, 0]
# Creating test data
test_data = ["test"] * 10
print(test_data) # 10 copies of "test"
# Building sequences
sequence = list(range(1, 4)) * 3
print(sequence) # [1, 2, 3, 1, 2, 3, 1, 2, 3]
# Understanding reference problem
# WRONG:
row = [0] * 3
matrix = [row] * 3 # All rows reference SAME list
matrix[0][0] = 5
print(matrix) # [[5,0,0], [5,0,0], [5,0,0]] - not what you want!
# CORRECT:
matrix = [[0] * 3 for _ in range(3)] # Independent rows
matrix[0][0] = 5
print(matrix) # [[5,0,0], [0,0,0], [0,0,0]]
1️⃣ .remove(item) – Remove by Value (First Occurrence)
Removes the FIRST occurrence of a specified value. Raises ValueError if not found.
# Basic removal
colors = ["red", "green", "blue", "green", "yellow"]
colors.remove("green") # Removes first 'green'
print(colors) # ['red', 'blue', 'green', 'yellow']
# Remove with duplicate values
numbers = [1, 2, 3, 2, 4, 2, 5]
numbers.remove(2)
print(numbers) # [1, 3, 2, 4, 2, 5] (first 2 removed)
# Error handling
try:
colors.remove("purple") # Not in list
except ValueError as e:
print(f"Error: {e}") # list.remove(x): x not in list
# Safe removal with check
if "purple" in colors:
colors.remove("purple")
else:
print("Item not found, skipping...")
# Remove all occurrences (loop)
def remove_all(lst, item):
"""Remove ALL occurrences of item from list"""
while item in lst:
lst.remove(item)
return lst
numbers = [1, 2, 3, 2, 4, 2, 5]
remove_all(numbers, 2)
print(numbers) # [1, 3, 4, 5]
🎯 Key Points:
- Time Complexity: O(n) (search + shift)
- Removes FIRST occurrence only
- Raises ValueError if not found
- Returns
None - Shifts subsequent elements left
🔍 Advanced remove() patterns:
# Remove by value with custom objects
class Person:
def __init__(self, name):
self.name = name
def __eq__(self, other):
return self.name == other.name
def __repr__(self):
return f"Person('{self.name}')"
people = [Person("Alice"), Person("Bob"), Person("Charlie")]
people.remove(Person("Bob")) # Works because __eq__ is defined
print(people) # [Person('Alice'), Person('Charlie')]
# Remove while iterating (WRONG way)
numbers = [1, 2, 3, 4, 5, 6]
# for num in numbers: # DON'T DO THIS!
# if num % 2 == 0:
# numbers.remove(num) # Modifies list while iterating
# print(numbers) # Unexpected results!
# CORRECT way: iterate over copy
numbers = [1, 2, 3, 4, 5, 6]
for num in numbers[:]: # Iterate over copy
if num % 2 == 0:
numbers.remove(num)
print(numbers) # [1, 3, 5]
# Using list comprehension (better for removing multiple)
numbers = [1, 2, 3, 4, 5, 6]
numbers = [num for num in numbers if num % 2 != 0]
print(numbers) # [1, 3, 5]
2️⃣ .pop([index]) – Remove by Index (Returns Removed Item)
Removes and RETURNS the item at the specified index. If no index given, removes and returns last item.
# Pop from end (most common)
fruits = ["apple", "banana", "mango", "orange"]
last = fruits.pop()
print(f"Removed: {last}") # Removed: orange
print(fruits) # ['apple', 'banana', 'mango']
# Pop from specific index
fruits = ["apple", "banana", "mango", "orange"]
second = fruits.pop(1) # Remove item at index 1
print(f"Removed: {second}") # Removed: banana
print(fruits) # ['apple', 'mango', 'orange']
# Pop from beginning
first = fruits.pop(0)
print(f"Removed: {first}") # Removed: apple
print(fruits) # ['mango', 'orange']
# Pop with negative indices
numbers = [10, 20, 30, 40, 50]
item = numbers.pop(-2) # Second from last
print(item) # 40
print(numbers) # [10, 20, 30, 50]
# Error handling
try:
fruits.pop(10) # Index out of range
except IndexError as e:
print(f"Error: {e}") # pop index out of range
🎯 Key Points:
- Time Complexity:
- pop() from end: O(1)
- pop(i) from middle: O(n)
- Returns the removed item
- Raises IndexError if index invalid
- Default index = -1 (last item)
🔍 Advanced pop() patterns:
# Using pop() to implement stack (LIFO)
stack = []
stack.append(1) # Push
stack.append(2)
stack.append(3)
print(stack) # [1, 2, 3]
item = stack.pop() # Pop
print(item) # 3
print(stack) # [1, 2]
# Using pop() to implement queue (FIFO) - but inefficient
queue = [1, 2, 3, 4, 5]
first = queue.pop(0) # O(n) - shifts all elements
print(first) # 1
print(queue) # [2, 3, 4, 5]
# Better: use collections.deque for queue
from collections import deque
queue = deque([1, 2, 3, 4, 5])
first = queue.popleft() # O(1)
print(first) # 1
print(queue) # deque([2, 3, 4, 5])
# Pop until list empty
fruits = ["apple", "banana", "mango"]
while fruits:
item = fruits.pop()
print(f"Processing: {item}")
# Processing: mango
# Processing: banana
# Processing: apple
# Pop with default value (custom function)
def pop_safe(lst, index= -1, default=None):
"""Safe pop that returns default instead of raising error"""
try:
return lst.pop(index)
except IndexError:
return default
numbers = [1, 2, 3]
print(pop_safe(numbers, 5, "not found")) # not found
3️⃣ del Statement – Delete by Index or Slice
Python's del statement can delete individual elements, slices, or the entire list.
# Delete single element
numbers = [10, 20, 30, 40, 50, 60]
del numbers[1] # Delete element at index 1
print(numbers) # [10, 30, 40, 50, 60]
# Delete slice
numbers = [10, 20, 30, 40, 50, 60]
del numbers[2:4] # Delete elements at indices 2 and 3
print(numbers) # [10, 20, 50, 60]
# Delete with step
numbers = [10, 20, 30, 40, 50, 60, 70, 80]
del numbers[1:6:2] # Delete indices 1,3,5
print(numbers) # [10, 30, 50, 70, 80]
# Delete all elements (clear list)
numbers = [1, 2, 3, 4, 5]
del numbers[:] # Delete all elements
print(numbers) # []
# Delete entire list
numbers = [1, 2, 3, 4, 5]
del numbers
# print(numbers) # NameError: name 'numbers' is not defined
# Delete using negative indices
numbers = [10, 20, 30, 40, 50]
del numbers[-2:] # Delete last two
print(numbers) # [10, 20, 30]
🎯 Key Points:
- Not a method – it's a statement
- Can delete single elements, slices, or entire list
- No return value
- Faster than pop() when you don't need the value
- Can delete variables completely
🔍 Advanced del patterns:
# Delete multiple non-consecutive elements (requires careful approach)
numbers = [10, 20, 30, 40, 50, 60, 70, 80]
# Delete elements at indices 1, 3, 5
indices_to_delete = [1, 3, 5]
# Delete from end to beginning to avoid index shifting
for i in sorted(indices_to_delete, reverse=True):
del numbers[i]
print(numbers) # [10, 30, 50, 70, 80]
# Delete every Nth element
numbers = list(range(20))
del numbers[::3] # Delete every 3rd element
print(numbers) # [1,2,4,5,7,8,10,11,13,14,16,17,19]
# Delete while iterating (safe with del)
numbers = [1, 2, 3, 4, 5, 6]
i = 0
while i < len(numbers):
if numbers[i] % 2 == 0:
del numbers[i] # No need to increment i (elements shift)
else:
i += 1
print(numbers) # [1, 3, 5]
# Using del to clear specific ranges
tasks = ["task1", "task2", "task3", "task4", "task5", "task6"]
# Delete completed tasks (indices 1-3)
del tasks[1:4]
print(tasks) # ['task1', 'task5', 'task6']
# Delete with negative step (reverse slice)
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
del numbers[8:2:-2] # Delete indices 8,6,4
print(numbers) # [1, 2, 3, 5, 7, 9, 10]
4️⃣ .clear() – Remove All Items
Removes all elements from the list, leaving an empty list while keeping the list object alive.
# Basic clear
fruits = ["apple", "banana", "mango"]
fruits.clear()
print(fruits) # []
# Verify list still exists
print(type(fruits)) #
print(len(fruits)) # 0
# Alternative ways to clear
numbers = [1, 2, 3, 4, 5]
# Method 1: clear()
numbers.clear()
print(numbers) # []
# Method 2: reassign to empty list
numbers = [1, 2, 3, 4, 5]
numbers = [] # Creates NEW empty list, old one garbage collected
print(numbers) # []
# Method 3: slice assignment
numbers = [1, 2, 3, 4, 5]
numbers[:] = [] # Clears in-place (same as clear())
print(numbers) # []
# Method 4: del with slice
numbers = [1, 2, 3, 4, 5]
del numbers[:] # Also clears in-place
print(numbers) # []
🎯 Key Points:
- Time Complexity: O(n) (removes references)
- Modifies list in-place
- Returns
None - Keeps the list object alive
- Different from reassigning to
[]
🔍 clear() vs reassignment:
# IMPORTANT: clear() vs reassignment
original_list = [1, 2, 3, 4, 5]
reference = original_list # Both refer to same list
# Using clear()
original_list.clear()
print(original_list) # []
print(reference) # [] (reference also cleared)
# Using reassignment
original_list = [1, 2, 3, 4, 5]
reference = original_list
original_list = [] # Reassign to new empty list
print(original_list) # [] (new list)
print(reference) # [1, 2, 3, 4, 5] (old list still exists!)
# Memory implications
import sys
def memory_usage(lst):
return sys.getsizeof(lst)
# clear() reuses memory
data = list(range(1000))
print(f"Before clear: {memory_usage(data)} bytes")
data.clear()
print(f"After clear: {memory_usage(data)} bytes") # Same memory location
# reassign creates new object
data = list(range(1000))
old_id = id(data)
data = [] # New object
new_id = id(data)
print(f"IDs different: {old_id != new_id}") # True
# Practical: reusing a list in a loop
def process_with_clear():
"""Efficient: reuse same list"""
results = []
for i in range(5):
# Clear but keep same list
results.clear()
results.extend([i, i*2, i*3])
print(f"Iteration {i}: {results}")
def process_with_reassign():
"""Less efficient: creates new lists"""
for i in range(5):
results = [] # Creates new list each iteration
results.extend([i, i*2, i*3])
print(f"Iteration {i}: {results}")
5️⃣ Filtering – Remove Items Conditionally
While not a built-in method, list comprehensions are the Pythonic way to remove items based on conditions.
# Remove all even numbers
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
odd_numbers = [n for n in numbers if n % 2 != 0]
print(odd_numbers) # [1, 3, 5, 7, 9]
# Remove strings shorter than 5 characters
words = ["apple", "cat", "banana", "dog", "elephant", "hi"]
long_words = [w for w in words if len(w) >= 5]
print(long_words) # ['apple', 'banana', 'elephant']
# Remove None values
data = [1, None, 2, None, 3, 4, None, 5]
clean_data = [x for x in data if x is not None]
print(clean_data) # [1, 2, 3, 4, 5]
# Remove duplicates (preserving order)
items = [1, 2, 2, 3, 3, 3, 4, 5, 5]
unique = []
[unique.append(x) for x in items if x not in unique]
print(unique) # [1, 2, 3, 4, 5]
# Remove items that match pattern
emails = ["user1@test.com", "spam@spam.com", "user2@test.com", "spam2@spam.com"]
valid_emails = [e for e in emails if "spam" not in e]
print(valid_emails) # ['user1@test.com', 'user2@test.com']
# Complex filtering with multiple conditions
numbers = list(range(1, 31))
filtered = [n for n in numbers
if n % 2 == 0 # Even
and n % 3 == 0 # Divisible by 3
and n > 10] # Greater than 10
print(filtered) # [12, 18, 24, 30]
1️⃣ .index(item, [start], [end]) – Find Position
Returns the index of the FIRST occurrence of an item. Can search within a slice.
# Basic usage
fruits = ["apple", "banana", "mango", "banana", "orange"]
pos = fruits.index("banana")
print(pos) # 1 (first occurrence)
# Search with start parameter
pos = fruits.index("banana", 2) # Start from index 2
print(pos) # 3
# Search within slice
pos = fruits.index("banana", 2, 4) # Search between indices 2-4
print(pos) # 3
# Error handling
try:
pos = fruits.index("grape")
except ValueError as e:
print("Item not found")
# Safe approach
def find_index(lst, item, default=-1):
try:
return lst.index(item)
except ValueError:
return default
print(find_index(fruits, "banana")) # 1
print(find_index(fruits, "grape")) # -1
🎯 Key Points:
- Time Complexity: O(n) (linear search)
- Returns FIRST occurrence only
- Raises ValueError if not found
- Optional start/end for slice search
🔍 Advanced index() patterns:
# Find all occurrences
def find_all_indices(lst, item):
return [i for i, x in enumerate(lst) if x == item]
fruits = ["apple", "banana", "mango", "banana", "orange", "banana"]
print(find_all_indices(fruits, "banana")) # [1, 3, 5]
# Find last occurrence
def find_last_index(lst, item):
indices = find_all_indices(lst, item)
return indices[-1] if indices else -1
print(find_last_index(fruits, "banana")) # 5
# Find nearest value
numbers = [10, 23, 45, 67, 89, 92]
def find_nearest(lst, target):
"""Find index of value closest to target"""
return min(range(len(lst)), key=lambda i: abs(lst[i] - target))
print(find_nearest(numbers, 50)) # 2 (value 45)
# Binary search on sorted list (much faster!)
import bisect
sorted_numbers = [10, 20, 30, 40, 50, 60, 70]
def binary_search_index(lst, item):
"""Find index using binary search (O(log n))"""
i = bisect.bisect_left(lst, item)
if i < len(lst) and lst[i] == item:
return i
return -1
print(binary_search_index(sorted_numbers, 40)) # 3
2️⃣ .count(item) – Count Occurrences
Returns the number of times an item appears in the list.
# Basic counting
numbers = [1, 2, 3, 2, 4, 2, 5, 2, 6]
print(numbers.count(2)) # 4
print(numbers.count(7)) # 0
# Count with different types
mixed = [1, "hello", 1, True, 1, 3.14, "hello"]
print(mixed.count(1)) # 3 (True counts as 1!)
print(mixed.count("hello")) # 2
print(mixed.count(True)) # 1 (only the explicit True)
# Count in nested lists
nested = [[1,2], [1,2], [3,4], [1,2]]
print(nested.count([1,2])) # 3
# Count with condition (using comprehension)
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
even_count = sum(1 for x in numbers if x % 2 == 0)
print(even_count) # 5
🎯 Key Points:
- Time Complexity: O(n)
- Returns integer count
- Returns 0 if item not found
- Works with any comparable type
🔍 Advanced count() patterns:
# Find most common element
def most_common(lst):
"""Return the most common element in list"""
if not lst:
return None
return max(set(lst), key=lst.count)
items = ["apple", "banana", "apple", "orange", "apple", "banana"]
print(most_common(items)) # apple
# Find least common element
def least_common(lst):
"""Return the least common element in list"""
if not lst:
return None
return min(set(lst), key=lst.count)
print(least_common(items)) # orange
# Frequency dictionary
def frequency_dict(lst):
"""Create dictionary of frequencies"""
return {item: lst.count(item) for item in set(lst)}
print(frequency_dict(items))
# {'apple': 3, 'banana': 2, 'orange': 1}
# Using collections.Counter (more efficient for large lists)
from collections import Counter
counter = Counter(items)
print(counter) # Counter({'apple': 3, 'banana': 2, 'orange': 1})
print(counter.most_common(2)) # [('apple', 3), ('banana', 2)]
# Count with multiple conditions
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
conditions_count = sum(1 for x in numbers
if x % 2 == 0 # even
and x % 3 == 0 # divisible by 3
and x > 5) # greater than 5
print(conditions_count) # 1 (only 6)
1️⃣ .sort(key=None, reverse=False) – In-Place Sorting
Sorts the list in-place. Does NOT return a new list.
# Basic sort (ascending)
numbers = [5, 2, 8, 1, 9, 3]
numbers.sort()
print(numbers) # [1, 2, 3, 5, 8, 9]
# Descending sort
numbers.sort(reverse=True)
print(numbers) # [9, 8, 5, 3, 2, 1]
# String sorting (alphabetical)
words = ["banana", "apple", "Cherry", "date"]
words.sort()
print(words) # ['Cherry', 'apple', 'banana', 'date'] (uppercase first!)
# Case-insensitive sort
words.sort(key=str.lower)
print(words) # ['apple', 'banana', 'Cherry', 'date']
# Sort by length
words.sort(key=len)
print(words) # ['date', 'apple', 'banana', 'Cherry']
# Sort by last character
words.sort(key=lambda x: x[-1])
print(words) # ['banana', 'apple', 'date', 'Cherry']
🎯 Key Points:
- Time Complexity: O(n log n) (Timsort)
- Modifies list in-place
- Returns
None - Stable sort (equal items keep order)
- Key parameter for custom sorting
🔍 Advanced sort() patterns:
# Sort list of tuples
students = [("Alice", 25), ("Bob", 20), ("Charlie", 23), ("David", 20)]
# Sort by age
students.sort(key=lambda x: x[1])
print(students)
# [('Bob', 20), ('David', 20), ('Charlie', 23), ('Alice', 25)]
# Sort by age, then by name
students.sort(key=lambda x: (x[1], x[0]))
print(students)
# [('Bob', 20), ('David', 20), ('Charlie', 23), ('Alice', 25)]
# Sort with multiple criteria
data = ["apple2", "Apple1", "banana3", "Banana2", "apple1"]
data.sort(key=lambda x: (x[0].lower(), x[-1]))
print(data) # ['Apple1', 'apple1', 'apple2', 'Banana2', 'banana3']
# Sort custom objects
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __repr__(self):
return f"{self.name}({self.age})"
people = [Person("Alice", 25), Person("Bob", 20), Person("Charlie", 23)]
people.sort(key=lambda p: p.age)
print(people) # [Bob(20), Charlie(23), Alice(25)]
# Sort with multiple keys using attrgetter
from operator import attrgetter
people.sort(key=attrgetter('age', 'name'))
print(people)
# Stable sort example
pairs = [(1, 'b'), (2, 'a'), (1, 'a'), (2, 'b')]
pairs.sort(key=lambda x: x[0]) # Sort only by first element
print(pairs) # [(1, 'b'), (1, 'a'), (2, 'a'), (2, 'b')] (order of second preserved)
# Sort with custom comparator (functools.cmp_to_key)
from functools import cmp_to_key
def compare(a, b):
"""Custom comparison: sort by length, then alphabetically"""
if len(a) != len(b):
return len(a) - len(b)
return (a > b) - (a < b)
words = ["banana", "apple", "cherry", "date", "fig"]
words.sort(key=cmp_to_key(compare))
print(words) # ['fig', 'date', 'apple', 'banana', 'cherry']
2️⃣ sorted(iterable, key=None, reverse=False) – Return New Sorted List
Returns a NEW sorted list. Original list remains unchanged. Works with ANY iterable.
# Basic usage
numbers = [5, 2, 8, 1, 9]
sorted_nums = sorted(numbers)
print(sorted_nums) # [1, 2, 5, 8, 9]
print(numbers) # [5, 2, 8, 1, 9] (unchanged)
# Descending
sorted_desc = sorted(numbers, reverse=True)
print(sorted_desc) # [9, 8, 5, 2, 1]
# Works with any iterable
text = "hello"
sorted_chars = sorted(text)
print(sorted_chars) # ['e', 'h', 'l', 'l', 'o']
# Sort tuple
tup = (5, 2, 8, 1, 9)
sorted_tup = sorted(tup)
print(sorted_tup) # [1, 2, 5, 8, 9] (returns list)
# Sort set
s = {5, 2, 8, 1, 9}
sorted_set = sorted(s)
print(sorted_set) # [1, 2, 5, 8, 9]
# Sort dictionary (by keys)
d = {'b': 2, 'a': 1, 'c': 3}
sorted_keys = sorted(d)
print(sorted_keys) # ['a', 'b', 'c']
🎯 Key Points:
- Time Complexity: O(n log n)
- Returns NEW list (copy)
- Original unchanged
- Works with ANY iterable
- More flexible than sort()
🔍 Advanced sorted() patterns:
# Sort dictionary by values
grades = {'Alice': 85, 'Bob': 92, 'Charlie': 78, 'David': 85}
# By value (ascending)
sorted_by_value = sorted(grades.items(), key=lambda x: x[1])
print(sorted_by_value)
# [('Charlie', 78), ('Alice', 85), ('David', 85), ('Bob', 92)]
# By value (descending) then by key
sorted_complex = sorted(grades.items(),
key=lambda x: (-x[1], x[0]))
print(sorted_complex)
# [('Bob', 92), ('Alice', 85), ('David', 85), ('Charlie', 78)]
# Sort list of strings by multiple criteria
files = ["file1.txt", "file2.py", "file10.txt", "file20.py", "file3.txt"]
# Natural sort (handles numbers correctly)
import re
def natural_key(text):
return [int(c) if c.isdigit() else c.lower()
for c in re.split('([0-9]+)', text)]
sorted_files = sorted(files, key=natural_key)
print(sorted_files)
# ['file1.txt', 'file2.py', 'file3.txt', 'file10.txt', 'file20.py']
# Sort by multiple attributes (using itemgetter)
from operator import itemgetter
data = [('Alice', 25, 'F'), ('Bob', 20, 'M'), ('Charlie', 25, 'M')]
sorted_data = sorted(data, key=itemgetter(1, 2, 0))
print(sorted_data)
# [('Bob', 20, 'M'), ('Alice', 25, 'F'), ('Charlie', 25, 'M')]
# Sort with custom key function
def custom_key(word):
"""Sort by: length (primary), vowel count (secondary), alphabet (tertiary)"""
vowel_count = sum(1 for c in word.lower() if c in 'aeiou')
return (len(word), -vowel_count, word)
words = ["python", "java", "javascript", "c", "cpp", "ruby"]
sorted_words = sorted(words, key=custom_key)
print(sorted_words)
# ['c', 'cpp', 'java', 'ruby', 'python', 'javascript']
3️⃣ .reverse() – In-Place Reversal
Reverses the elements of the list in-place.
# Basic reversal
numbers = [1, 2, 3, 4, 5]
numbers.reverse()
print(numbers) # [5, 4, 3, 2, 1]
# Reverse with strings
words = ["apple", "banana", "cherry"]
words.reverse()
print(words) # ['cherry', 'banana', 'apple']
# Reverse empty list
empty = []
empty.reverse()
print(empty) # []
# Reverse nested lists
nested = [[1,2], [3,4], [5,6]]
nested.reverse()
print(nested) # [[5,6], [3,4], [1,2]]
# Note: reverse() does NOT sort, just reverses order
🎯 Key Points:
- Time Complexity: O(n)
- Modifies list in-place
- Returns
None - Just reverses, doesn't sort
- Different from
reversed()function
🔍 reverse() alternatives and patterns:
# Using reversed() function (creates iterator)
numbers = [1, 2, 3, 4, 5]
rev_iter = reversed(numbers)
print(list(rev_iter)) # [5, 4, 3, 2, 1]
print(numbers) # [1, 2, 3, 4, 5] (unchanged)
# Slicing to reverse (creates new list)
numbers = [1, 2, 3, 4, 5]
reversed_slice = numbers[::-1]
print(reversed_slice) # [5, 4, 3, 2, 1]
print(numbers) # [1, 2, 3, 4, 5] (unchanged)
# Performance comparison
import time
data = list(range(1000000))
# Method 1: reverse() - fastest, in-place
start = time.time()
data.reverse()
rev_time = time.time() - start
# Method 2: reversed() + list()
data = list(range(1000000))
start = time.time()
reversed_list = list(reversed(data))
rev_func_time = time.time() - start
# Method 3: slicing
data = list(range(1000000))
start = time.time()
reversed_slice = data[::-1]
slice_time = time.time() - start
print(f"reverse(): {rev_time:.4f}s")
print(f"reversed(): {rev_func_time:.4f}s")
print(f"slicing: {slice_time:.4f}s")
# Practical: palindrome checker
def is_palindrome(lst):
"""Check if list reads same forwards and backwards"""
return lst == lst[::-1]
print(is_palindrome([1, 2, 3, 2, 1])) # True
print(is_palindrome([1, 2, 3, 4, 5])) # False
# Reverse in chunks
def reverse_chunks(lst, chunk_size):
"""Reverse each chunk of the list"""
return [item for i in range(0, len(lst), chunk_size)
for item in reversed(lst[i:i+chunk_size])]
numbers = list(range(1, 13))
print(reverse_chunks(numbers, 4))
# [4, 3, 2, 1, 8, 7, 6, 5, 12, 11, 10, 9]
⚠️ CRITICAL: Assignment Does NOT Copy!
list2 = list1 creates a REFERENCE, not a copy. Both variables point to the SAME list object.
❌ WRONG: Reference Assignment
list1 = [1, 2, 3]
list2 = list1 # This is NOT a copy!
list2.append(4)
print(list1) # [1, 2, 3, 4] (Original changed!)
print(list2) # [1, 2, 3, 4]
# Even reassignment affects both
list2[0] = 99
print(list1) # [99, 2, 3, 4]
print(list2) # [99, 2, 3, 4]
# Check identity
print(list1 is list2) # True (same object)
✅ CORRECT: Actual Copies
list1 = [1, 2, 3]
# Method 1: copy() method
list2 = list1.copy()
# Method 2: slicing
list3 = list1[:]
# Method 3: list() constructor
list4 = list(list1)
list2.append(4)
list3.append(5)
list4.append(6)
print(list1) # [1, 2, 3] (Original unchanged)
print(list2) # [1, 2, 3, 4]
print(list3) # [1, 2, 3, 5]
print(list4) # [1, 2, 3, 6]
# Check identities
print(list1 is list2) # False (different objects)
🧠 Shallow Copy vs Deep Copy – CRITICAL for Nested Lists
📦 Shallow Copy
import copy
nested = [[1, 2], [3, 4], [5, 6]]
# All shallow copy methods
shallow1 = nested.copy()
shallow2 = nested[:]
shallow3 = list(nested)
# Modify nested element in shallow copy
shallow1[0].append(99)
print("Original nested:", nested)
# [[1, 2, 99], [3, 4], [5, 6]] (Original CHANGED!)
print("Shallow copy:", shallow1)
# [[1, 2, 99], [3, 4], [5, 6]]
# WHY? Shallow copy copies REFERENCES to inner lists
print("Inner list IDs:")
print(f"Original[0] id: {id(nested[0])}")
print(f"Shallow[0] id: {id(shallow1[0])}") # SAME ID!
🔋 Deep Copy
import copy
nested = [[1, 2], [3, 4], [5, 6]]
# Deep copy - completely independent
deep = copy.deepcopy(nested)
# Modify nested element in deep copy
deep[0].append(99)
deep[1].append(100)
print("Original nested:", nested)
# [[1, 2], [3, 4], [5, 6]] (Original UNCHANGED!)
print("Deep copy:", deep)
# [[1, 2, 99], [3, 4, 100], [5, 6]]
# Different inner lists
print(f"Original[0] id: {id(nested[0])}")
print(f"Deep[0] id: {id(deep[0])}") # DIFFERENT IDs!
📊 Copy Method Comparison
| Method | Syntax | Shallow/Deep | Speed | When to Use |
|---|---|---|---|---|
copy() |
new = old.copy() |
Shallow | Fast | Simple lists, no nesting |
| Slicing | new = old[:] |
Shallow | Fast | Pythonic, works everywhere |
list() |
new = list(old) |
Shallow | Fast | When converting from other iterables |
copy.deepcopy() |
new = copy.deepcopy(old) |
Deep | Slower | Nested lists, complex structures |
🔍 Advanced copying examples:
# 1. Copy with modifications
def copy_and_modify(lst, index, new_value):
"""Create copy and modify single element"""
new_list = lst.copy()
new_list[index] = new_value
return new_list
original = [1, 2, 3, 4, 5]
modified = copy_and_modify(original, 2, 99)
print(original) # [1, 2, 3, 4, 5]
print(modified) # [1, 2, 99, 4, 5]
# 2. Copy with transformations
def copy_and_transform(lst, func):
"""Create copy with each element transformed"""
return [func(x) for x in lst]
numbers = [1, 2, 3, 4, 5]
squares = copy_and_transform(numbers, lambda x: x**2)
print(squares) # [1, 4, 9, 16, 25]
# 3. Partial deep copy (custom)
def partial_deep_copy(lst, levels=1):
"""Deep copy only specified levels deep"""
if levels == 0:
return lst
return [partial_deep_copy(item, levels-1) if isinstance(item, list)
else item for item in lst]
nested = [[1, [2, 3]], [4, [5, 6]]]
copy1 = partial_deep_copy(nested, 1) # Only top level deep
copy2 = partial_deep_copy(nested, 2) # Two levels deep
copy1[0][1].append(99) # Modifies original at level 2
copy2[1][1].append(100) # Independent
print(nested) # [[1, [2, 3, 99]], [4, [5, 6]]]
1️⃣ List Repetition (* Operator)
# Create repeated patterns
zeros = [0] * 10
print(zeros) # [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
pattern = [1, 2, 3] * 4
print(pattern) # [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
# Create 2D lists (careful!)
# WRONG:
matrix_wrong = [[0] * 3] * 3
matrix_wrong[0][0] = 5
print(matrix_wrong) # [[5,0,0], [5,0,0], [5,0,0]] - all rows changed!
# CORRECT:
matrix_correct = [[0] * 3 for _ in range(3)]
matrix_correct[0][0] = 5
print(matrix_correct) # [[5,0,0], [0,0,0], [0,0,0]]
# Create test data
test_data = ["test"] * 5
print(test_data) # ['test', 'test', 'test', 'test', 'test']
2️⃣ List to String (join)
fruits = ["apple", "banana", "mango"]
# Basic join
result = ", ".join(fruits)
print(result) # "apple, banana, mango"
# Different separators
print(" - ".join(fruits)) # "apple - banana - mango"
print("".join(fruits)) # "applebananamango"
print("\n".join(fruits)) # Each on new line
# Join with condition
words = ["hello", "", "world", None, "python"]
# Filter out None and empty strings
clean_words = [w for w in words if w]
print(" ".join(clean_words)) # "hello world python"
# Join numbers (must convert to string)
numbers = [1, 2, 3, 4, 5]
result = ", ".join(str(n) for n in numbers)
print(result) # "1, 2, 3, 4, 5"
3️⃣ String to List (split)
sentence = "Python is awesome"
# Split by whitespace
words = sentence.split()
print(words) # ['Python', 'is', 'awesome']
# Split by comma
csv = "apple,banana,mango,orange"
items = csv.split(",")
print(items) # ['apple', 'banana', 'mango', 'orange']
# Split with maxsplit
data = "one two three four five"
first_two = data.split(" ", 2) # Split only first 2 spaces
print(first_two) # ['one', 'two', 'three four five']
# Split lines
multiline = """Line 1
Line 2
Line 3"""
lines = multiline.split("\n")
print(lines) # ['Line 1', 'Line 2', 'Line 3']
# Split and convert to numbers
numbers_str = "1,2,3,4,5"
numbers = [int(x) for x in numbers_str.split(",")]
print(numbers) # [1, 2, 3, 4, 5]
4️⃣ List Unpacking
# Basic unpacking
fruits = ["apple", "banana", "mango"]
a, b, c = fruits
print(a) # apple
print(b) # banana
print(c) # mango
# Unpack with * (extended unpacking)
first, *rest = [1, 2, 3, 4, 5]
print(first) # 1
print(rest) # [2, 3, 4, 5]
*begin, last = [1, 2, 3, 4, 5]
print(begin) # [1, 2, 3, 4]
print(last) # 5
first, *middle, last = [1, 2, 3, 4, 5]
print(first) # 1
print(middle) # [2, 3, 4]
print(last) # 5
# Unpacking in loops
pairs = [[1, 2], [3, 4], [5, 6]]
for a, b in pairs:
print(f"{a} + {b} = {a+b}")
# 1 + 2 = 3
# 3 + 4 = 7
# 5 + 6 = 11
# Swap variables using unpacking
x, y = 10, 20
x, y = y, x
print(x, y) # 20 10
5️⃣ List as Stack (LIFO)
stack = []
# Push items
stack.append(1)
stack.append(2)
stack.append(3)
print(stack) # [1, 2, 3]
# Pop items
top = stack.pop()
print(top) # 3
print(stack) # [1, 2]
# Peek at top without removing
if stack:
print(stack[-1]) # 2
# Check if empty
while stack:
item = stack.pop()
print(f"Processing: {item}")
6️⃣ List as Queue (FIFO) – Better with deque
# List as queue (inefficient for large lists)
queue = []
# Enqueue
queue.append(1)
queue.append(2)
queue.append(3)
# Dequeue (O(n) - shifts all elements!)
first = queue.pop(0)
print(first) # 1
print(queue) # [2, 3]
# BETTER: Use collections.deque
from collections import deque
dq = deque()
# Enqueue
dq.append(1)
dq.append(2)
dq.append(3)
# Dequeue (O(1))
first = dq.popleft()
print(first) # 1
print(dq) # deque([2, 3])
| Method | Time Complexity | Space Complexity | In-Place? | Return Value |
|---|---|---|---|---|
append() | O(1)* | O(1) | Yes | None |
insert() | O(n) | O(1) | Yes | None |
extend() | O(k) | O(k) | Yes | None |
remove() | O(n) | O(1) | Yes | None |
pop() (end) | O(1) | O(1) | Yes | Item |
pop(i) | O(n) | O(1) | Yes | Item |
clear() | O(n) | O(1) | Yes | None |
index() | O(n) | O(1) | No | Integer |
count() | O(n) | O(1) | No | Integer |
sort() | O(n log n) | O(n) | Yes | None |
sorted() | O(n log n) | O(n) | No | New list |
reverse() | O(n) | O(1) | Yes | None |
copy() | O(n) | O(n) | No | New list |
⚡ Quick Performance Tips:
- Use
append()instead ofinsert(0)for better performance - Use
extend()instead of multipleappend()calls - Use list comprehensions instead of loops with
append() - For frequent membership tests, convert to
set() - Use
dequefor frequent insertions/removals at both ends
✂️ 11.3 List Slicing – The Complete Master Guide
🔷 What is Slicing?
Slicing is a technique to extract a portion (sub-list) from a list by specifying a range of indices. It creates a new list containing the selected elements.
# Basic syntax: list[start:stop:step]
# - start: starting index (inclusive)
# - stop: ending index (exclusive)
# - step: increment between indices
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
slice1 = numbers[2:7] # From index 2 to 6
slice2 = numbers[2:7:2] # From index 2 to 6, step 2
slice3 = numbers[::] # Entire list (copy)
🎯 Key Points:
- Slicing always returns a NEW list
- Original list remains unchanged
- All parameters are optional
- Indices can be positive or negative
📊 Slice Parameters – Complete Reference
| Parameter | Description | Default | Valid Values | Example |
|---|---|---|---|---|
start |
Index where slice begins (inclusive) | 0 (beginning) |
Any integer: 0 to len-1, negative indices | [2:5] starts at index 2 |
stop |
Index where slice ends (exclusive) | len(list) (end) |
Any integer > start for positive step | [2:5] stops before index 5 |
step |
Increment between indices | 1 |
Non-zero integer (positive or negative) | [::2] takes every 2nd element |
🗺️ Visual Index Map – The Key to Understanding Slicing
List: [ 10, 20, 30, 40, 50, 60, 70, 80 ] Index: 0 1 2 3 4 5 6 7 Negative: -8 -7 -6 -5 -4 -3 -2 -1 Visual representation: ┌────┬────┬────┬────┬────┬────┬────┬────┐ │ 10 │ 20 │ 30 │ 40 │ 50 │ 60 │ 70 │ 80 │ └────┴────┴────┴────┴────┴────┴────┴────┘ 0 1 2 3 4 5 6 7 -8 -7 -6 -5 -4 -3 -2 -1
data = [10, 20, 30, 40, 50, 60, 70, 80]
# 1. Both start and stop specified
print(data[2:5]) # [30, 40, 50] (indices 2,3,4)
# 2. Omit start (starts from beginning)
print(data[:4]) # [10, 20, 30, 40]
# 3. Omit stop (goes to end)
print(data[5:]) # [60, 70, 80]
# 4. Omit both (full copy)
print(data[:]) # [10, 20, 30, 40, 50, 60, 70, 80]
# 5. Start greater than stop (empty slice)
print(data[5:2]) # [] (empty list)
# 6. Start equals stop (empty slice)
print(data[3:3]) # []
data = [10, 20, 30, 40, 50, 60, 70, 80]
# 7. Last 3 elements
print(data[-3:]) # [60, 70, 80]
# 8. First 3 elements (using negative)
print(data[:-5]) # [10, 20, 30] (same as [:3])
# 9. Middle slice with negative
print(data[-5:-2]) # [40, 50, 60] (indices -5,-4,-3)
# 10. All except last 2
print(data[:-2]) # [10, 20, 30, 40, 50, 60]
# 11. All except first 2
print(data[2:]) # [30, 40, 50, 60, 70, 80]
# 12. Last element as list
print(data[-1:]) # [80] (not 80)
data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 13. Every 2nd element
print(data[::2]) # [0, 2, 4, 6, 8]
# 14. Every 3rd element
print(data[::3]) # [0, 3, 6, 9]
# 15. Start + step combination
print(data[1:8:2]) # [1, 3, 5, 7]
# 16. Step with negative indices
print(data[-8::2]) # [2, 4, 6, 8]
# 17. Large step (> length)
print(data[::10]) # [0] (only first)
# 18. Step = 1 (default)
print(data[2:7:1]) # [2, 3, 4, 5, 6]
data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 19. Reverse entire list
print(data[::-1]) # [9,8,7,6,5,4,3,2,1,0]
# 20. Reverse from index 7 down to 2
print(data[7:2:-1]) # [7,6,5,4,3]
# 21. Reverse with step 2
print(data[::-2]) # [9,7,5,3,1]
# 22. Last 3 in reverse
print(data[-1:-4:-1]) # [9,8,7]
# 23. First 3 in reverse
print(data[2::-1]) # [2,1,0]
# 24. Complex negative step
print(data[8:1:-3]) # [8,5,2]
📋 Slicing Rules Summary
✅ Positive Step (Forward):
- start must be < stop for non-empty slice
- Elements: start, start+step, start+2step...
- Default start: 0, default stop: len(list)
✅ Negative Step (Backward):
- start must be > stop for non-empty slice
- Elements: start, start+step, start+2step...
- Default start: -1, default stop: -len(list)-1
1️⃣ Slice Assignment – Modify Parts of List
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
# Replace slice with new values
numbers[2:5] = [30, 40, 50]
print(numbers) # [1, 2, 30, 40, 50, 6, 7, 8, 9]
# Replace with different length (list expands/shrinks)
numbers[5:7] = [60, 70, 80, 90] # Insert more elements
print(numbers) # [1, 2, 30, 40, 50, 60, 70, 80, 90, 8, 9]
# Replace with fewer elements (shrinks)
numbers[1:4] = [20] # Replace 3 elements with 1
print(numbers) # [1, 20, 50, 60, 70, 80, 90, 8, 9]
# Insert without replacing (using step=0 slice)
numbers[3:3] = [55, 56] # Insert at index 3
print(numbers) # [1, 20, 50, 55, 56, 60, 70, 80, 90, 8, 9]
2️⃣ Slice Deletion – Remove Parts of List
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
# Delete slice
numbers[2:5] = []
print(numbers) # [1, 2, 6, 7, 8, 9]
# Using del with slice
del numbers[3:]
print(numbers) # [1, 2, 6]
# Delete with step
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
del numbers[1::2] # Delete every 2nd element
print(numbers) # [1, 3, 5, 7, 9]
# Clear entire list using slice
numbers[:] = []
print(numbers) # []
3️⃣ Slicing with Strings
text = "Python Programming"
# String slicing works the same way
print(text[0:6]) # "Python"
print(text[7:]) # "Programming"
print(text[::-1]) # "gnimmargorP nohtyP"
# Extract every 2nd character
print(text[::2]) # "Pto rgamn"
# Reverse words
words = text.split()
reversed_words = [word[::-1] for word in words]
print(reversed_words) # ['nohtyP', 'gnimmargorP']
# Palindrome checker using slicing
def is_palindrome(s):
return s == s[::-1]
print(is_palindrome("radar")) # True
print(is_palindrome("python")) # False
4️⃣ Slicing with Tuples
tup = (10, 20, 30, 40, 50, 60)
# Tuple slicing returns new tuple
print(tup[1:4]) # (20, 30, 40)
print(tup[::-1]) # (60, 50, 40, 30, 20, 10)
# Cannot modify tuples (immutable)
# tup[1:3] = (25, 35) # TypeError!
# Useful for extracting data
coordinates = (10, 20, 30, 40, 50)
x, *rest = coordinates[:3]
print(x, rest) # 10 [20, 30]
5️⃣ Slice Objects – Reusable Slices
# Create reusable slice objects
first_three = slice(3)
last_two = slice(-2, None)
middle = slice(2, 5)
every_other = slice(None, None, 2)
data = [10, 20, 30, 40, 50, 60, 70]
print(data[first_three]) # [10, 20, 30]
print(data[last_two]) # [60, 70]
print(data[middle]) # [30, 40, 50]
print(data[every_other]) # [10, 30, 50, 70]
# Slice objects have attributes
print(f"Start: {middle.start}, Stop: {middle.stop}, Step: {middle.step}")
# Useful for applying same slice to multiple lists
def apply_slice_to_multiple(slice_obj, *lists):
return [lst[slice_obj] for lst in lists]
list1 = [1,2,3,4,5]
list2 = [6,7,8,9,10]
list3 = [11,12,13,14,15]
result = apply_slice_to_multiple(slice(1,4), list1, list2, list3)
print(result) # [[2,3,4], [7,8,9], [12,13,14]]
6️⃣ Slicing with Step = 0?
# Step cannot be 0!
# numbers[::0] # ValueError: slice step cannot be zero
# But step can be any other integer
print([1,2,3,4,5][::2]) # [1,3,5] (step 2)
print([1,2,3,4,5][::-1]) # [5,4,3,2,1] (step -1)
print([1,2,3,4,5][::1]) # [1,2,3,4,5] (step 1)
# Step larger than list
print([1,2,3][::10]) # [1] (only first)
# Step with negative and out of range
print([1,2,3,4,5][-1:-10:-2]) # [5,3,1]
📊 Data Analysis
# Sample data: temperature readings
temperatures = [22.5, 23.1, 21.8, 24.2, 25.0, 26.1, 24.8, 23.9]
# Get first week (first 7 days)
week1 = temperatures[:7]
# Get last 3 days
last_3_days = temperatures[-3:]
# Get every other reading
sparse_data = temperatures[::2]
# Remove outliers (skip first and last)
core_data = temperatures[1:-1]
# Moving average (simple)
def moving_average(data, window=3):
return [sum(data[i:i+window])/window
for i in range(len(data)-window+1)]
print(moving_average(temperatures))
🃏 Card Games & Shuffling
# Card deck simulation
cards = list(range(52)) # 0-51 represents cards
# Deal cards
def deal_cards(deck, players=4):
hands = []
for i in range(players):
hand = deck[i::players] # Every 4th card starting at i
hands.append(hand)
return hands
deck = list(range(52))
hands = deal_cards(deck)
for i, hand in enumerate(hands):
print(f"Player {i+1}: {len(hand)} cards")
# Perfect shuffle (riffle)
def perfect_shuffle(deck):
mid = len(deck) // 2
first_half = deck[:mid]
second_half = deck[mid:]
shuffled = []
for a, b in zip(first_half, second_half):
shuffled.extend([a, b])
return shuffled
print(perfect_shuffle([1,2,3,4,5,6])) # [1,4,2,5,3,6]
📝 Text Processing
# Extract file extensions
filenames = ["document.txt", "image.jpg", "script.py", "data.csv"]
extensions = [f[-3:] for f in filenames]
print(extensions) # ['txt', 'jpg', 'py', 'csv']
# Get domain from email
emails = ["user@gmail.com", "admin@company.co.uk", "info@test.org"]
domains = [e[e.index('@')+1:] for e in emails]
print(domains) # ['gmail.com', 'company.co.uk', 'test.org']
# Truncate text
def truncate(text, max_length=20, suffix="..."):
if len(text) <= max_length:
return text
return text[:max_length-len(suffix)] + suffix
print(truncate("This is a very long sentence that needs truncation", 20))
# "This is a very lo..."
# Get first and last characters
word = "Python"
print(f"First: {word[0]}, Last: {word[-1]}")
📈 Financial Calculations
# Stock prices
prices = [100, 102, 101, 105, 107, 106, 108, 110]
# Calculate daily returns
daily_returns = [(prices[i] - prices[i-1])/prices[i-1] * 100
for i in range(1, len(prices))]
print(f"Daily returns: {daily_returns}")
# Moving crossover strategy
short_ma = sum(prices[-5:]) / 5 # 5-day moving average
long_ma = sum(prices[-20:]) / 20 # 20-day moving average
# Calculate momentum (current vs 10 days ago)
if len(prices) >= 10:
momentum = (prices[-1] - prices[-10]) / prices[-10] * 100
print(f"10-day momentum: {momentum:.2f}%")
# Split data into training and testing
train_size = int(len(prices) * 0.8)
train_data = prices[:train_size]
test_data = prices[train_size:]
print(f"Train: {train_data}, Test: {test_data}")
🎮 Game Development
# Game board representation
board = [['' for _ in range(3)] for _ in range(3)]
# Get row
row = board[1] # Second row
# Get column
col = [row[1] for row in board] # Second column
# Get diagonal
diag1 = [board[i][i] for i in range(3)] # Main diagonal
diag2 = [board[i][2-i] for i in range(3)] # Anti-diagonal
# Check win condition
def check_win(board, player):
# Check rows
if any(all(cell == player for cell in row) for row in board):
return True
# Check columns
if any(all(board[r][c] == player for r in range(3)) for c in range(3)):
return True
# Check diagonals
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
🔬 Scientific Computing
# Signal processing
signal = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# Downsample signal
downsampled = signal[::2]
print(f"Downsampled: {downsampled}")
# Create overlapping windows
def create_windows(data, window_size, step=1):
return [data[i:i+window_size]
for i in range(0, len(data)-window_size+1, step)]
windows = create_windows(signal, 3, 2)
print(f"Windows: {windows}") # [[0,1,2], [2,3,4], [4,5,6], [6,7,8]]
# Padding sequences
def pad_sequence(seq, target_length, pad_value=0):
if len(seq) >= target_length:
return seq[:target_length]
return seq + [pad_value] * (target_length - len(seq))
print(pad_sequence([1,2,3], 5)) # [1,2,3,0,0]
🎯 Common Slicing Idioms
data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 1. Copy a list
copy1 = data[:] # Most Pythonic
copy2 = data.copy() # Also good
# 2. Reverse a list
reversed_list = data[::-1]
# 3. Remove first and last
middle = data[1:-1]
# 4. First n elements
first_3 = data[:3]
# 5. Last n elements
last_3 = data[-3:]
# 6. Every other element
every_other = data[::2]
# 7. Reverse every other
reverse_every_other = data[::-2]
# 8. Rotate list
rotate_left = data[1:] + data[:1] # [2,3,4,5,1]
rotate_right = data[-1:] + data[:-1] # [10,1,2,3,4,5,6,7,8,9]
⚠️ Common Pitfalls & Solutions
# Pitfall 1: Forgetting slicing creates a copy
original = [1,2,3,4,5]
sliced = original[2:4]
sliced[0] = 99
print(original) # [1,2,3,4,5] (unchanged - good!)
# Pitfall 2: Step cannot be zero
# data[::0] # ValueError!
# Pitfall 3: Off-by-one errors
data = [1,2,3,4,5]
# WRONG: Want first 3 elements
wrong = data[1:3] # [2,3] (wrong!)
# CORRECT:
correct = data[:3] # [1,2,3]
# Pitfall 4: Negative step confusion
data = [1,2,3,4,5]
# This returns empty list
empty = data[2:4:-1] # [] (start < stop with negative step)
# Correct for reverse:
correct = data[4:2:-1] # [5,4,3]
# Pitfall 5: Modifying while iterating
# Instead of:
# for item in data[2:5]:
# modify(item)
# Use:
for item in data[2:5]: # This is safe (works on copy)
pass
⚡ Performance Tips
import time
# Slicing is fast (creates new list)
data = list(range(1000000))
# Fast: slicing
start = time.time()
sliced = data[500000:500100]
slice_time = time.time() - start
# Slower: manual loop
start = time.time()
manual = [data[i] for i in range(500000, 500100)]
loop_time = time.time() - start
print(f"Slicing time: {slice_time:.6f}s")
print(f"Loop time: {loop_time:.6f}s") # Slicing is faster
# Memory consideration: slicing creates new list
# For large slices, consider using itertools.islice for memory efficiency
from itertools import islice
def slice_memory_efficient(lst, start, stop):
return list(islice(lst, start, stop))
# Reusing slices with slice objects (faster for repeated use)
my_slice = slice(2, 8, 2)
for _ in range(100):
result = data[my_slice] # Reuse same slice
🎨 Creative Slicing Examples
# 1. Get alternating elements with offset
data = [1,2,3,4,5,6,7,8,9,10]
offset_0 = data[0::3] # [1,4,7,10]
offset_1 = data[1::3] # [2,5,8]
offset_2 = data[2::3] # [3,6,9]
# 2. Create a checkerboard pattern
matrix = [[1,2,3,4],
[5,6,7,8],
[9,10,11,12],
[13,14,15,16]]
black_squares = [matrix[i][j] for i in range(4)
for j in range(4) if (i+j) % 2 == 0]
# 3. Pagination
def paginate(items, page_size, page_num):
start = (page_num - 1) * page_size
end = start + page_size
return items[start:end]
items = list(range(1, 101))
page_2 = paginate(items, 10, 2) # Items 11-20
# 4. Running average
def running_average(data, window):
return [sum(data[i:i+window])/window
for i in range(len(data)-window+1)]
# 5. Extract diagonals from matrix
matrix = [[1,2,3], [4,5,6], [7,8,9]]
diag1 = [matrix[i][i] for i in range(3)]
diag2 = [matrix[i][2-i] for i in range(3)]
Given data = [10, 20, 30, 40, 50, 60], what is data[-2:]?
What does [1,2,3,4,5][::-2] return?
How to get all elements except first and last?
What is the result of [1,2,3,4,5][10:20]?
How to reverse a string "Python" using slicing?
What does data[::] do?
🏆 Challenge Problems
# Challenge 1: Rotate list left by n positions
def rotate_left(lst, n):
n = n % len(lst) # Handle n > len(lst)
return lst[n:] + lst[:n]
print(rotate_left([1,2,3,4,5], 2)) # [3,4,5,1,2]
# Challenge 2: Get every nth element starting from offset
def every_nth(lst, n, offset=0):
return lst[offset::n]
print(every_nth([1,2,3,4,5,6,7,8,9,10], 3, 1)) # [2,5,8]
# Challenge 3: Split list into chunks
def chunk_list(lst, chunk_size):
return [lst[i:i+chunk_size] for i in range(0, len(lst), chunk_size)]
print(chunk_list([1,2,3,4,5,6,7,8], 3)) # [[1,2,3], [4,5,6], [7,8]]
# Challenge 4: Remove every nth element
def remove_every_nth(lst, n):
return [x for i, x in enumerate(lst) if (i + 1) % n != 0]
print(remove_every_nth([1,2,3,4,5,6,7,8,9], 3)) # [1,2,4,5,7,8]
| Operation | Code | Result (for [10,20,30,40,50,60]) |
|---|---|---|
| First 3 elements | [:3] | [10,20,30] |
| Last 3 elements | [-3:] | [40,50,60] |
| Elements 2-4 | [1:4] | [20,30,40] |
| All except first 2 | [2:] | [30,40,50,60] |
| All except last 2 | [:-2] | [10,20,30,40] |
| Every 2nd element | [::2] | [10,30,50] |
| Every 2nd from index 1 | [1::2] | [20,40,60] |
| Reverse list | [::-1] | [60,50,40,30,20,10] |
| Reverse every 2nd | [::-2] | [60,40,20] |
| Middle element | [len//2:len//2+1] | [40] (when len=6) |
| First and last | [0] + [-1] | [10,60] |
| Remove first and last | [1:-1] | [20,30,40,50] |
| Copy entire list | [:] | [10,20,30,40,50,60] |
🥪 11.4 Nested Lists – The Complete Master Guide
🔷 Definition
A nested list is a list that appears as an element inside another list. This creates a hierarchical structure where each element can itself be a list, allowing for multi-dimensional data representation.
# Basic nested list structure
nested_list = [ [1, 2, 3], # First inner list (row 0)
[4, 5, 6], # Second inner list (row 1)
[7, 8, 9] ] # Third inner list (row 2)
# Think of it like a table:
# Col0 Col1 Col2
# Row0: 1 2 3
# Row1: 4 5 6
# Row2: 7 8 9
🎯 Key Characteristics:
- Can have any depth (2D, 3D, 4D...)
- Inner lists can have different lengths
- Access with multiple indices:
list[row][col] - Perfect for matrices, tables, game boards
🗺️ Visual Representation of Nested Lists
2D List (Matrix): ┌─────────────┐ │ [1, 2, 3] │ ← Row 0 │ [4, 5, 6] │ ← Row 1 │ [7, 8, 9] │ ← Row 2 └─────────────┘ Access: matrix[1][2] = 6 3D List (Cube): ┌─────────────────┐ │ ┌─────┐ │ │ │[1,2]│ [3,4] │ ← Layer 0 │ └─────┘ │ │ ┌─────┐ │ │ │[5,6]│ [7,8] │ ← Layer 1 │ └─────┘ │ └─────────────────┘ Access: cube[1][0][1] = 6
1️⃣ Manual Creation (Explicit)
# 2x3 matrix
matrix = [
[1, 2, 3],
[4, 5, 6]
]
# Jagged list (rows of different lengths)
jagged = [
[1, 2],
[3, 4, 5],
[6],
[7, 8, 9, 10]
]
2️⃣ Using List Comprehension
# Create 3x4 matrix filled with zeros
zeros = [[0 for _ in range(4)] for _ in range(3)]
print(zeros)
# [[0,0,0,0], [0,0,0,0], [0,0,0,0]]
# Create identity matrix (3x3)
identity = [[1 if i == j else 0 for j in range(3)] for i in range(3)]
print(identity)
# [[1,0,0], [0,1,0], [0,0,1]]
# Multiplication table (10x10)
table = [[i*j for j in range(1,11)] for i in range(1,11)]
3️⃣ Using Loops
# Build matrix row by row
matrix = []
for i in range(3):
row = []
for j in range(4):
row.append(i * 4 + j + 1)
matrix.append(row)
print(matrix)
# [[1,2,3,4], [5,6,7,8], [9,10,11,12]]
4️⃣ From External Data
# From CSV data
csv_data = """1,2,3
4,5,6
7,8,9"""
matrix = [list(map(int, line.split(',')))
for line in csv_data.split('\n')]
# From list of pairs
pairs = [(1,2), (3,4), (5,6)]
matrix = [list(pair) for pair in pairs]
5️⃣ Using numpy (for comparison)
# import numpy as np
# np.array([[1,2,3], [4,5,6]]) # NumPy arrays are different!
6️⃣ Empty nested list structures
# Create empty 3x4 matrix
empty = [[] for _ in range(3)]
# Later fill:
empty[0] = [1,2,3,4]
empty[1] = [5,6,7,8]
empty[2] = [9,10,11,12]
🔹 Basic Indexing
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
# Get entire row
print(matrix[0]) # [1, 2, 3]
print(matrix[1]) # [4, 5, 6]
print(matrix[2]) # [7, 8, 9]
# Get single element
print(matrix[0][0]) # 1
print(matrix[1][1]) # 5
print(matrix[2][2]) # 9
# Get element with negative indices
print(matrix[-1][-1]) # 9 (last row, last col)
print(matrix[0][-2]) # 2 (first row, second last col)
🔹 Accessing Columns
# Get first column
col0 = [row[0] for row in matrix]
print(col0) # [1, 4, 7]
# Get second column
col1 = [row[1] for row in matrix]
print(col1) # [2, 5, 8]
# Get diagonal
diag = [matrix[i][i] for i in range(3)]
print(diag) # [1, 5, 9]
# Get anti-diagonal
anti_diag = [matrix[i][2-i] for i in range(3)]
print(anti_diag) # [3, 5, 7]
🔹 3D List Access
cube = [
[[1,2], [3,4]],
[[5,6], [7,8]],
[[9,10], [11,12]]
]
# Access layers
print(cube[0]) # [[1,2], [3,4]]
print(cube[1]) # [[5,6], [7,8]]
print(cube[2]) # [[9,10], [11,12]]
# Access rows within layer
print(cube[0][0]) # [1,2]
print(cube[0][1]) # [3,4]
# Access individual elements
print(cube[1][0][1]) # 6
print(cube[2][1][0]) # 11
🔹 Slicing Nested Lists
matrix = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12]
]
# Get first two rows
print(matrix[:2]) # [[1,2,3,4], [5,6,7,8]]
# Get first two elements of each row
sliced = [row[:2] for row in matrix]
print(sliced) # [[1,2], [5,6], [9,10]]
# Get submatrix (rows 0-1, cols 1-2)
submatrix = [row[1:3] for row in matrix[:2]]
print(submatrix) # [[2,3], [6,7]]
1️⃣ Changing Single Elements
matrix = [[1,2,3], [4,5,6], [7,8,9]]
# Change single element
matrix[1][1] = 99
print(matrix) # [[1,2,3], [4,99,6], [7,8,9]]
# Change entire row
matrix[0] = [10,11,12]
print(matrix) # [[10,11,12], [4,99,6], [7,8,9]]
2️⃣ Adding Rows
# Append new row
matrix.append([13,14,15])
print(matrix)
# [[10,11,12], [4,99,6], [7,8,9], [13,14,15]]
# Insert row at specific position
matrix.insert(1, [20,21,22])
print(matrix)
# [[10,11,12], [20,21,22], [4,99,6], [7,8,9], [13,14,15]]
3️⃣ Adding Columns
matrix = [[1,2], [3,4], [5,6]]
# Add column with value 0 to each row
for row in matrix:
row.append(0)
print(matrix) # [[1,2,0], [3,4,0], [5,6,0]]
# Add column with different values
values = [7,8,9]
for i, row in enumerate(matrix):
row.append(values[i])
print(matrix) # [[1,2,0,7], [3,4,0,8], [5,6,0,9]]
# Insert column at specific position
pos = 1
value = 99
for row in matrix:
row.insert(pos, value)
print(matrix) # [[1,99,2,0,7], [3,99,4,0,8], [5,99,6,0,9]]
4️⃣ Removing Rows
matrix = [[1,2,3], [4,5,6], [7,8,9], [10,11,12]]
# Remove last row
matrix.pop()
print(matrix) # [[1,2,3], [4,5,6], [7,8,9]]
# Remove by index
del matrix[1]
print(matrix) # [[1,2,3], [7,8,9]]
# Remove by value (if row matches)
matrix.remove([1,2,3])
print(matrix) # [[7,8,9]]
5️⃣ Removing Columns
matrix = [[1,2,3], [4,5,6], [7,8,9]]
# Remove last column from each row
for row in matrix:
row.pop()
print(matrix) # [[1,2], [4,5], [7,8]]
# Remove specific column (index 0)
for row in matrix:
del row[0]
print(matrix) # [[2], [5], [8]]
# Remove column using list comprehension
matrix = [[1,2,3], [4,5,6], [7,8,9]]
col_to_remove = 1
matrix = [[val for i, val in enumerate(row) if i != col_to_remove]
for row in matrix]
print(matrix) # [[1,3], [4,6], [7,9]]
1️⃣ Matrix Addition
A = [[1,2], [3,4]]
B = [[5,6], [7,8]]
def matrix_add(A, B):
"""Add two matrices of same dimensions"""
if len(A) != len(B) or len(A[0]) != len(B[0]):
raise ValueError("Matrices must have same dimensions")
return [[A[i][j] + B[i][j] for j in range(len(A[0]))]
for i in range(len(A))]
print(matrix_add(A, B)) # [[6,8], [10,12]]
2️⃣ Matrix Multiplication
def matrix_multiply(A, B):
"""Multiply two matrices"""
if len(A[0]) != len(B):
raise ValueError("Invalid dimensions for multiplication")
result = [[0 for _ in range(len(B[0]))] for _ in range(len(A))]
for i in range(len(A)):
for j in range(len(B[0])):
for k in range(len(B)):
result[i][j] += A[i][k] * B[k][j]
return result
A = [[1,2], [3,4]]
B = [[5,6], [7,8]]
print(matrix_multiply(A, B)) # [[19,22], [43,50]]
3️⃣ Matrix Transpose
def transpose(matrix):
"""Return transpose of matrix"""
return [[matrix[j][i] for j in range(len(matrix))]
for i in range(len(matrix[0]))]
matrix = [[1,2,3], [4,5,6]]
print(transpose(matrix)) # [[1,4], [2,5], [3,6]]
# Using zip (elegant one-liner)
transpose_zip = list(zip(*matrix))
print(transpose_zip) # [(1,4), (2,5), (3,6)]
4️⃣ Determinant (2x2)
def determinant2x2(matrix):
"""Calculate determinant of 2x2 matrix"""
if len(matrix) != 2 or len(matrix[0]) != 2:
raise ValueError("Matrix must be 2x2")
return matrix[0][0]*matrix[1][1] - matrix[0][1]*matrix[1][0]
matrix = [[4,6], [3,8]]
print(determinant2x2(matrix)) # 14 (4*8 - 6*3)
5️⃣ Row/Column Operations
matrix = [[1,2,3], [4,5,6], [7,8,9]]
# Sum of each row
row_sums = [sum(row) for row in matrix]
print(row_sums) # [6, 15, 24]
# Sum of each column
col_sums = [sum(row[i] for row in matrix) for i in range(3)]
print(col_sums) # [12, 15, 18]
# Maximum in each row
row_max = [max(row) for row in matrix]
print(row_max) # [3, 6, 9]
# Minimum in each column
col_min = [min(row[i] for row in matrix) for i in range(3)]
print(col_min) # [1, 2, 3]
6️⃣ Rotating Matrix
def rotate_90_clockwise(matrix):
"""Rotate matrix 90 degrees clockwise"""
return [list(reversed(col)) for col in zip(*matrix)]
def rotate_90_counterclockwise(matrix):
"""Rotate matrix 90 degrees counter-clockwise"""
return [list(col) for col in zip(*matrix)][::-1]
matrix = [[1,2,3], [4,5,6], [7,8,9]]
print(rotate_90_clockwise(matrix))
# [[7,4,1], [8,5,2], [9,6,3]]
print(rotate_90_counterclockwise(matrix))
# [[3,6,9], [2,5,8], [1,4,7]]
🎮 Game Development – Tic-Tac-Toe
# Tic-Tac-Toe board
board = [[' ' for _ in range(3)] for _ in range(3)]
def print_board(board):
for row in board:
print('|'.join(row))
print('-'*5)
def check_winner(board):
# Check rows
for row in board:
if row[0] == row[1] == row[2] != ' ':
return row[0]
# Check columns
for col in range(3):
if board[0][col] == board[1][col] == board[2][col] != ' ':
return board[0][col]
# Check diagonals
if board[0][0] == board[1][1] == board[2][2] != ' ':
return board[0][0]
if board[0][2] == board[1][1] == board[2][0] != ' ':
return board[0][2]
return None
# Make moves
board[0][0] = 'X'
board[1][1] = 'O'
board[2][2] = 'X'
print_board(board)
📊 Spreadsheet/Excel Simulation
# Simple spreadsheet
sheet = [[0 for _ in range(5)] for _ in range(10)]
def set_cell(sheet, row, col, value):
sheet[row][col] = value
def get_cell(sheet, row, col):
return sheet[row][col]
def sum_range(sheet, r1, c1, r2, c2):
total = 0
for i in range(r1, r2+1):
for j in range(c1, c2+1):
total += sheet[i][j]
return total
# Example usage
set_cell(sheet, 0, 0, 10)
set_cell(sheet, 0, 1, 20)
set_cell(sheet, 1, 0, 30)
set_cell(sheet, 1, 1, 40)
print(sum_range(sheet, 0, 0, 1, 1)) # 100
🗺️ Image Processing (Grayscale)
# 5x5 grayscale image (0-255)
image = [
[255, 200, 150, 100, 50],
[200, 150, 100, 50, 0],
[150, 100, 50, 0, 50],
[100, 50, 0, 50, 100],
[50, 0, 50, 100, 150]
]
def apply_filter(image, kernel_size=3):
"""Simple average filter"""
result = [[0 for _ in range(len(image[0]))] for _ in range(len(image))]
offset = kernel_size // 2
for i in range(offset, len(image)-offset):
for j in range(offset, len(image[0])-offset):
total = 0
for ki in range(-offset, offset+1):
for kj in range(-offset, offset+1):
total += image[i+ki][j+kj]
result[i][j] = total // (kernel_size * kernel_size)
return result
smoothed = apply_filter(image)
📦 Inventory Management
# Warehouse inventory [aisle][shelf][bin]
warehouse = [
[ # Aisle 0
[10, 20, 15], # Shelf 0
[5, 8, 12], # Shelf 1
[0, 3, 7] # Shelf 2
],
[ # Aisle 1
[25, 30, 22],
[18, 14, 16],
[9, 11, 13]
]
]
def check_inventory(warehouse, aisle, shelf, bin):
return warehouse[aisle][shelf][bin]
def update_inventory(warehouse, aisle, shelf, bin, amount):
warehouse[aisle][shelf][bin] += amount
def total_inventory(warehouse):
total = 0
for aisle in warehouse:
for shelf in aisle:
for bin in shelf:
total += bin
return total
print(f"Total items: {total_inventory(warehouse)}")
update_inventory(warehouse, 0, 0, 1, -5) # Remove 5 items
🧪 Scientific Data – Temperature Records
# Temperature readings: [city][day][hour]
temperatures = [
[ # City 0: New York
[15, 16, 18, 20], # Day 0
[14, 15, 17, 19], # Day 1
[13, 14, 16, 18] # Day 2
],
[ # City 1: Los Angeles
[20, 22, 25, 23],
[19, 21, 24, 22],
[18, 20, 23, 21]
]
]
def city_average(temp, city):
"""Average temperature for a city across all days/hours"""
total = 0
count = 0
for day in temp[city]:
for hour in day:
total += hour
count += 1
return total / count
def daily_average(temp, city, day):
"""Average temperature for a specific day"""
return sum(temp[city][day]) / len(temp[city][day])
print(f"NYC average: {city_average(temperatures, 0):.1f}°C")
print(f"LA day 1 avg: {daily_average(temperatures, 1, 1):.1f}°C")
🎯 Sudoku Board
# Sudoku puzzle representation
sudoku = [
[5,3,0, 0,7,0, 0,0,0],
[6,0,0, 1,9,5, 0,0,0],
[0,9,8, 0,0,0, 0,6,0],
[8,0,0, 0,6,0, 0,0,3],
[4,0,0, 8,0,3, 0,0,1],
[7,0,0, 0,2,0, 0,0,6],
[0,6,0, 0,0,0, 2,8,0],
[0,0,0, 4,1,9, 0,0,5],
[0,0,0, 0,8,0, 0,7,9]
]
def get_row(board, row):
return board[row]
def get_col(board, col):
return [board[row][col] for row in range(9)]
def get_box(board, box_row, box_col):
"""Get 3x3 box"""
result = []
for i in range(box_row*3, box_row*3+3):
for j in range(box_col*3, box_col*3+3):
result.append(board[i][j])
return result
# Check if placement is valid
def is_valid(board, row, col, num):
# Check row
if num in get_row(board, row):
return False
# Check column
if num in get_col(board, col):
return False
# Check box
if num in get_box(board, row//3, col//3):
return False
return True
❌ Pitfall 1: Creating with Multiplication
# WRONG WAY - All rows reference the SAME list!
wrong = [[0] * 3] * 3
wrong[0][0] = 5
print(wrong) # [[5,0,0], [5,0,0], [5,0,0]] (all rows changed!)
# WHY? [0]*3 creates one list, then *3 creates 3 references to it
# CORRECT WAY - List comprehension
correct = [[0] * 3 for _ in range(3)]
correct[0][0] = 5
print(correct) # [[5,0,0], [0,0,0], [0,0,0]]
# Also correct using loops
correct = []
for _ in range(3):
correct.append([0] * 3)
❌ Pitfall 2: Shallow Copy Issues
import copy
original = [[1,2], [3,4]]
# Shallow copy - inner lists are shared
shallow = original.copy()
shallow[0].append(99)
print(original) # [[1,2,99], [3,4]] (original changed!)
# Deep copy - completely independent
deep = copy.deepcopy(original)
deep[1].append(100)
print(original) # [[1,2,99], [3,4]] (unchanged)
print(deep) # [[1,2,99], [3,4,100]]
❌ Pitfall 3: Index Errors
matrix = [[1,2], [3,4]]
# Accessing out of bounds
# print(matrix[2][0]) # IndexError: list index out of range
# print(matrix[0][2]) # IndexError: list index out of range
# Safe access function
def safe_access(matrix, i, j, default=None):
if 0 <= i < len(matrix) and 0 <= j < len(matrix[i]):
return matrix[i][j]
return default
print(safe_access(matrix, 2, 0, "N/A")) # N/A
❌ Pitfall 4: Jagged List Assumptions
jagged = [[1,2], [3,4,5], [6]]
# Assuming all rows have same length
for row in jagged:
print(row[1]) # Works for first two rows, IndexError for third
# Safe approach
for row in jagged:
if len(row) > 1:
print(row[1])
else:
print("Row too short")
❌ Pitfall 5: Modifying While Iterating
matrix = [[1,2], [3,4], [5,6]]
# WRONG - modifying while iterating
# for row in matrix:
# if sum(row) > 5:
# matrix.remove(row) # Dangerous!
# CORRECT - iterate over copy
for row in matrix[:]:
if sum(row) > 5:
matrix.remove(row)
✅ Best Practices Summary
- Use list comprehensions for creating nested lists
- Always use deep copy for independent copies
- Check dimensions before accessing
- Handle jagged lists appropriately
- Use try/except for robust code
- Consider NumPy for large numerical matrices
1️⃣ List Comprehension (2D)
nested = [[1,2], [3,4], [5,6]]
flat = [item for sublist in nested for item in sublist]
print(flat) # [1, 2, 3, 4, 5, 6]
2️⃣ Using sum() (Not recommended)
flat = sum(nested, [])
print(flat) # [1, 2, 3, 4, 5, 6]
# Warning: Inefficient for large lists (quadratic time)
3️⃣ Using itertools.chain
from itertools import chain
flat = list(chain.from_iterable(nested))
print(flat) # [1, 2, 3, 4, 5, 6]
4️⃣ Recursive Flattening (Any Depth)
def flatten_recursive(nested):
"""Flatten nested lists of any depth"""
result = []
for item in nested:
if isinstance(item, list):
result.extend(flatten_recursive(item))
else:
result.append(item)
return result
deep_nested = [1, [2, [3, 4], 5], [6, 7], 8]
print(flatten_recursive(deep_nested)) # [1,2,3,4,5,6,7,8]
5️⃣ Using numpy (if available)
# import numpy as np
# arr = np.array(nested)
# flat = arr.flatten().tolist()
Performance Comparison
# Speed: list comp ≈ chain > sum
# Memory: list comp creates new list
# Use chain for large lists (generator-based)
Given matrix = [[1,2], [3,4], [5,6]], how do you access the value 4?
What's wrong with matrix = [[0]*3]*3?
How to get the second column from a matrix?
How to flatten [[1,2],[3,4]] into [1,2,3,4]?
🏆 Challenge Problems
# Challenge 1: Create a multiplication table (1-10)
table = [[i*j for j in range(1,11)] for i in range(1,11)]
# Challenge 2: Check if matrix is symmetric
def is_symmetric(matrix):
n = len(matrix)
return all(matrix[i][j] == matrix[j][i]
for i in range(n) for j in range(n))
# Challenge 3: Rotate matrix 180 degrees
def rotate_180(matrix):
return [row[::-1] for row in matrix[::-1]]
# Challenge 4: Find saddle point (min in row, max in col)
def find_saddle_point(matrix):
for i, row in enumerate(matrix):
min_val = min(row)
col_idx = row.index(min_val)
if min_val == max(matrix[j][col_idx] for j in range(len(matrix))):
return (i, col_idx, min_val)
return None
⚡ 11.5 List Comprehension – The Complete Master Guide
🔷 Definition
List comprehension is a concise syntax for creating lists based on existing iterables (like ranges, strings, tuples, or other lists). It consists of brackets containing an expression followed by a for clause, then zero or more for or if clauses.
# Basic syntax: [expression for item in iterable if condition]
# Components:
# 1. Expression: What to put in the new list (can be any Python expression)
# 2. Item: Variable representing each element
# 3. Iterable: Source data (list, range, string, tuple, etc.)
# 4. Condition: Optional filter (only items satisfying condition are included)
# Example breakdown:
squares = [x**2 # Expression: square the value
for x # Item: each element from source
in range(10) # Iterable: numbers 0-9
if x % 2 == 0] # Condition: only even numbers
# Result: [0, 4, 16, 36, 64]
🎯 Key Benefits:
- Concise: 1 line vs 4-5 lines with loops
- Faster: 20-30% speed improvement
- Readable: Expresses intent clearly
- Functional: Declarative programming style
🔄 Traditional Loop vs List Comprehension
❌ Traditional Loop (4 lines)
squares = []
for i in range(1, 11):
squares.append(i ** 2)
print(squares)
# [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
✅ List Comprehension (1 line)
squares = [i ** 2 for i in range(1, 11)]
print(squares)
# [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
1️⃣ Simple Transformation
# Square numbers
squares = [x**2 for x in range(1, 11)]
# [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
# Convert to string
nums = [str(x) for x in range(1, 6)]
# ['1', '2', '3', '4', '5']
# Double each element
numbers = [1, 2, 3, 4, 5]
doubled = [x * 2 for x in numbers]
# [2, 4, 6, 8, 10]
2️⃣ With Condition (Filtering)
# Even numbers
evens = [x for x in range(1, 21) if x % 2 == 0]
# [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
# Numbers divisible by 3 and 5
special = [x for x in range(1, 51) if x % 3 == 0 and x % 5 == 0]
# [15, 30, 45]
# Strings with length > 3
words = ["cat", "elephant", "dog", "butterfly", "ant"]
long_words = [w for w in words if len(w) > 3]
# ['elephant', 'butterfly']
3️⃣ String Operations
text = "Hello World Python"
# Uppercase
upper_chars = [char.upper() for char in text if char.isalpha()]
# ['H','E','L','L','O','W','O','R','L','D','P','Y','T','H','O','N']
# Extract vowels
vowels = [char for char in text.lower() if char in 'aeiou']
# ['e','o','o','o']
# Get ASCII values
ascii_vals = [ord(char) for char in "ABC"]
# [65, 66, 67]
4️⃣ With Range and Math
# Cubes
cubes = [x**3 for x in range(1, 6)]
# [1, 8, 27, 64, 125]
# Square roots
import math
roots = [math.sqrt(x) for x in [4, 9, 16, 25]]
# [2.0, 3.0, 4.0, 5.0]
# Factorials (using math.factorial)
facts = [math.factorial(x) for x in range(1, 6)]
# [1, 2, 6, 24, 120]
1️⃣ Single Condition (if)
# Basic filtering
numbers = [-5, -3, -1, 0, 2, 4, 6, 8]
positive = [n for n in numbers if n > 0]
# [2, 4, 6, 8]
# Multiple conditions with 'and'
special = [n for n in range(1, 31)
if n % 2 == 0 and n % 3 == 0 and n % 5 == 0]
# [30] (only 30 divisible by 2,3,5)
# Multiple conditions with 'or'
valid = [n for n in range(1, 11) if n % 2 == 0 or n % 3 == 0]
# [2, 3, 4, 6, 8, 9, 10]
2️⃣ If-Else (Ternary)
# Categorize numbers
numbers = [1, 2, 3, 4, 5, 6]
categories = ["even" if x % 2 == 0 else "odd" for x in numbers]
# ['odd', 'even', 'odd', 'even', 'odd', 'even']
# Replace negative numbers with 0
nums = [-5, 3, -2, 7, -1, 4]
non_negative = [x if x >= 0 else 0 for x in nums]
# [0, 3, 0, 7, 0, 4]
# Absolute values
abs_values = [x if x >= 0 else -x for x in nums]
# [5, 3, 2, 7, 1, 4]
# Grade assignment
scores = [85, 62, 95, 78, 45, 91]
grades = ["A" if s >= 90 else "B" if s >= 80 else "C" if s >= 70
else "D" if s >= 60 else "F" for s in scores]
# ['B', 'D', 'A', 'C', 'F', 'A']
3️⃣ Nested Conditions
# Multiple if conditions (and implied)
nums = range(1, 31)
result = [x for x in nums if x > 10 if x < 20 if x % 2 == 0]
# [12, 14, 16, 18] (same as x > 10 and x < 20 and x % 2 == 0)
# Complex filtering
data = [1, "hello", 3.14, True, None, [1,2], "world", 42]
# Get only strings with length > 3
strings = [x for x in data if isinstance(x, str) and len(x) > 3]
# ['hello', 'world']
4️⃣ Conditional Expression in Expression Part
# Apply different transformations
numbers = [1, 2, 3, 4, 5, 6]
transformed = [x**2 if x % 2 == 0 else x**3 for x in numbers]
# [1, 4, 27, 16, 125, 36]
# (odd: cube, even: square)
# Format based on value
values = [0, 15, 25, 35, 45, 55]
labels = ["low" if v < 20 else "medium" if v < 40 else "high"
for v in values]
# ['low', 'low', 'medium', 'medium', 'high', 'high']
1️⃣ Flattening Matrices
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
# Flatten to 1D list
flat = [num for row in matrix for num in row]
# [1, 2, 3, 4, 5, 6, 7, 8, 9]
# With condition (only even numbers)
even_flat = [num for row in matrix for num in row if num % 2 == 0]
# [2, 4, 6, 8]
# Reading order: for row in matrix: for num in row: num
2️⃣ Cartesian Products
colors = ["red", "blue", "green"]
sizes = ["S", "M", "L"]
# All combinations
products = [(color, size) for color in colors for size in sizes]
# [('red','S'), ('red','M'), ('red','L'), ('blue','S'), ...]
# With condition (no "red" with "L")
filtered = [(c, s) for c in colors for s in sizes
if not (c == "red" and s == "L")]
# All combos except ('red','L')
3️⃣ Creating Matrices
# Create 3x3 identity matrix
identity = [[1 if i == j else 0 for j in range(3)] for i in range(3)]
# [[1,0,0], [0,1,0], [0,0,1]]
# Create multiplication table
mult_table = [[i * j for j in range(1, 11)] for i in range(1, 11)]
# Create chess board (8x8)
chess_board = [["W" if (i+j) % 2 == 0 else "B" for j in range(8)]
for i in range(8)]
# Alternate black and white squares
4️⃣ Matrix Transpose
matrix = [[1,2,3], [4,5,6], [7,8,9]]
# Transpose using nested comprehension
transpose = [[row[i] for row in matrix] for i in range(3)]
# [[1,4,7], [2,5,8], [3,6,9]]
# Using zip (simpler)
transpose_zip = [list(col) for col in zip(*matrix)]
5️⃣ 3D List Comprehension
# Create 3x3x3 cube
cube = [[[0 for _ in range(3)] for _ in range(3)] for _ in range(3)]
# Fill with values based on indices
filled_cube = [[[i+j+k for k in range(3)] for j in range(3)]
for i in range(3)]
# 3D matrix with sums of indices
6️⃣ Complex Nested Operations
# Extract all consonants from a sentence
sentence = "The quick brown fox jumps"
consonants = [char for word in sentence.split()
for char in word if char.lower() not in 'aeiou']
# ['T','h','q','c','k','b','r','w','n','f','x','j','m','p','s']
1️⃣ Prime Numbers
# Find primes up to 50
def is_prime(n):
if n < 2:
return False
for i in range(2, int(n**0.5) + 1):
if n % i == 0:
return False
return True
primes = [x for x in range(2, 51) if is_prime(x)]
# [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]
# One-liner (not recommended for readability)
primes_oneliner = [x for x in range(2, 51)
if all(x % y != 0 for y in range(2, int(x**0.5)+1))]
2️⃣ Fibonacci Sequence
# Generate first 20 Fibonacci numbers
fib = [0, 1]
[fib.append(fib[-2] + fib[-1]) for _ in range(18)]
# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181]
3️⃣ Data Cleaning
# Remove None, empty strings, and whitespace
data = ["hello", "", " ", None, "world", " python ", None]
cleaned = [item.strip() for item in data
if item and item.strip()]
# ['hello', 'world', 'python']
# Convert strings to numbers safely
str_nums = ["1", "2", "three", "4", "five", "6"]
numbers = [int(x) for x in str_nums if x.isdigit()]
# [1, 2, 4, 6]
4️⃣ Text Processing
# Word length distribution
text = "Python list comprehensions are powerful and elegant"
word_lengths = [len(word) for word in text.split()]
# [6, 4, 13, 3, 8, 3, 7]
# Extract email domains
emails = ["user@gmail.com", "admin@company.com", "info@test.org"]
domains = [email.split('@')[1] for email in emails]
# ['gmail.com', 'company.com', 'test.org']
5️⃣ Working with Dictionaries
# Create dictionary from two lists
keys = ['a', 'b', 'c']
values = [1, 2, 3]
dictionary = {k: v for k, v in zip(keys, values)}
# {'a': 1, 'b': 2, 'c': 3}
# Filter dictionary items
scores = {'Alice': 85, 'Bob': 92, 'Charlie': 78, 'David': 88}
high_scores = {name: score for name, score in scores.items()
if score > 80}
# {'Alice': 85, 'Bob': 92, 'David': 88}
6️⃣ Set and Dictionary Comprehensions
# Set comprehension (unique squares)
numbers = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
unique_squares = {x**2 for x in numbers}
# {1, 4, 9, 16}
# Dictionary comprehension with condition
squares_dict = {x: x**2 for x in range(1, 6) if x % 2 == 0}
# {2: 4, 4: 16}
⚡ Speed Comparison
import timeit
# Test with 1 million iterations
def test_loop():
result = []
for i in range(1_000_000):
result.append(i ** 2)
return result
def test_comprehension():
return [i ** 2 for i in range(1_000_000)]
# Measure time
loop_time = timeit.timeit(test_loop, number=10)
comp_time = timeit.timeit(test_comprehension, number=10)
print(f"Loop: {loop_time:.4f} seconds")
print(f"Comprehension: {comp_time:.4f} seconds")
print(f"Comprehension is {loop_time/comp_time:.2f}x faster")
# Comprehension is typically 1.2-1.5x faster
📈 Memory Efficiency
import sys
# List comprehension creates full list
comprehension = [x**2 for x in range(1000)]
comp_size = sys.getsizeof(comprehension)
# Generator expression (memory efficient)
generator = (x**2 for x in range(1000))
gen_size = sys.getsizeof(generator)
print(f"List comprehension size: {comp_size} bytes")
print(f"Generator expression size: {gen_size} bytes")
# Generator uses much less memory
# When to use each:
# - Use list comprehension when you need all values at once
# - Use generator for large sequences (memory constrained)
📋 Performance Guidelines
| Operation | Loop Time (1M) | Comprehension Time | Speedup |
|---|---|---|---|
| Simple transformation | 0.35s | 0.28s | 25% faster |
| With condition | 0.42s | 0.31s | 35% faster |
| Nested loops | 0.89s | 0.67s | 33% faster |
| String operations | 0.51s | 0.39s | 31% faster |
❌ Pitfall 1: Overcomplicating
# TOO COMPLEX - Hard to read
complex = [x for y in range(10) for z in range(y)
if x := y*z if x % 2 == 0 if x > 10]
# BETTER - Break into steps or use regular loops
temp = []
for y in range(10):
for z in range(y):
val = y * z
if val % 2 == 0 and val > 10:
temp.append(val)
❌ Pitfall 2: Side Effects
# BAD - Using comprehension for side effects
[print(x) for x in range(5)] # Works but wrong!
# GOOD - Use regular loop
for x in range(5):
print(x)
# BAD - Modifying external variable
total = 0
[total := total + x for x in range(10)] # Don't!
# GOOD - Use sum() or loop
total = sum(range(10))
✅ Best Practice 1: Readability
# GOOD - Clear and readable
squares = [x**2 for x in range(10) if x % 2 == 0]
# GOOD - Break long comprehensions
result = [
complex_expression(x, y)
for x in range(100)
for y in range(100)
if condition(x, y)
]
✅ Best Practice 2: Use Appropriate Tools
# For simple transformations: list comprehension
squares = [x**2 for x in range(10)]
# For complex logic: regular loop
result = []
for item in data:
if complex_condition(item):
processed = heavy_processing(item)
result.append(processed)
# For memory efficiency: generator expression
squares_gen = (x**2 for x in range(1000000))
📋 List Comprehension Cheat Sheet
| Pattern | Syntax | Example |
|---|---|---|
| Basic | [expr for item in iter] | [x**2 for x in range(5)] |
| With condition | [expr for item in iter if cond] | [x for x in nums if x > 0] |
| If-else | [expr1 if cond else expr2 for item in iter] | ['even' if x%2==0 else 'odd' for x in nums] |
| Nested loops | [expr for a in A for b in B] | [x*y for x in [1,2] for y in [3,4]] |
| Nested with condition | [expr for a in A for b in B if cond] | [(x,y) for x in range(3) for y in range(3) if x!=y] |
| Matrix flatten | [item for row in matrix for item in row] | [num for row in mat for num in row] |
| Matrix creation | [[expr for j in range(cols)] for i in range(rows)] | [[0 for _ in range(3)] for _ in range(4)] |
📝 Syntax and Usage
# Generator expression uses () instead of []
squares_gen = (x**2 for x in range(10))
# Generator doesn't store all values at once
print(squares_gen) #
# Iterate through generator
for val in squares_gen:
print(val, end=' ') # 0 1 4 9 16 25 36 49 64 81
# Convert to list if needed
squares_list = list(squares_gen) # Empty if generator consumed!
💾 Memory Comparison
import sys
# List comprehension - stores all values
list_comp = [x**2 for x in range(1000000)]
list_size = sys.getsizeof(list_comp)
# Generator expression - lazy evaluation
gen_exp = (x**2 for x in range(1000000))
gen_size = sys.getsizeof(gen_exp)
print(f"List size: {list_size:,} bytes")
print(f"Generator size: {gen_size:,} bytes")
# Generator uses tiny constant memory
📊 When to Use Which
| Use List Comprehension When: | Use Generator Expression When: |
|---|---|
| Need to access elements multiple times | Only need to iterate once |
| Need random access by index | Processing large datasets |
| Need to know length (len()) | Memory is constrained |
| Passing to functions that need sequences | Pipelining operations |
Convert to list comprehension: result = []
for i in range(10):
if i % 2 == 0:
result.append(i*2)
Create a list of squares for numbers 1-10 using comprehension
Flatten [[1,2], [3,4], [5,6]] using comprehension
Create list of all possible (x,y) pairs where x,y in 1-3 and x != y
🏆 Challenge Problems
# Challenge 1: Find all numbers divisible by 7 but not by 5 between 1-100
answer1 = [x for x in range(1, 101) if x % 7 == 0 and x % 5 != 0]
# [7, 14, 21, 28, 42, 49, 56, 63, 77, 84, 91, 98]
# Challenge 2: Extract all vowels from a string with their positions
text = "Hello World"
vowels_with_pos = [(i, char) for i, char in enumerate(text)
if char.lower() in 'aeiou']
# [(1, 'e'), (4, 'o'), (7, 'o')]
# Challenge 3: Create multiplication table as list of lists
table = [[i*j for j in range(1, 11)] for i in range(1, 11)]
# Challenge 4: Find all prime numbers between 1-100 (one-liner)
primes = [x for x in range(2, 101)
if all(x % y != 0 for y in range(2, int(x**0.5)+1))]
# Challenge 5: Transpose a matrix using comprehension
matrix = [[1,2,3], [4,5,6], [7,8,9]]
transpose = [[row[i] for row in matrix] for i in range(len(matrix[0]))]
🎓 Module 11 : Python List (Ordered Collection) Successfully Completed
You have successfully completed this module of Python for Cybersecurity.
Keep building your expertise step by step — Learn Next Module →
📗 Python Tuple – The Complete Master Guide
📚 12.1 What is a Tuple? – The Complete Guide
A tuple is an ordered, immutable collection of elements. Once created, you cannot add, remove, or change any element. This immutability makes tuples faster, safer, and more memory-efficient than lists.
📖 Real-World Analogy
- 🗺️ GPS Coordinates: (28.6139, 77.2090) – never change
- 📅 Days of Week: ("Mon", "Tue", "Wed") – fixed
- 🎨 RGB Colors: (255, 0, 0) – constant values
- 🆔 Personal Info: ("Amit", 101, "BCA") – permanent record
🐍 Python Example
# Creating a tuple
fruits = ("apple", "banana", "mango")
numbers = (10, 20, 30, 40)
mixed = ("John", 25, True, 12.5)
print(type(fruits)) #
print(len(fruits)) # 3
🔑 Key Characteristics of Tuples
fruits = ("apple", "banana", "mango")
# fruits[0] = "orange" # ❌ TypeError: 'tuple' object does not support item assignment
# fruits.append("grape") # ❌ AttributeError: no append method
# Once created, it's FOREVER fixed!
t1 = (1, 2, 3)
t2 = (3, 2, 1)
print(t1 == t2) # False (order matters!)
# Elements maintain their insertion order
# Tuples can hold ANY data type
mixed = (
"Hello", # string
42, # integer
3.14, # float
True, # boolean
[1, 2, 3], # list (mutable inside!)
{"key": "value"}, # dictionary
(4, 5, 6) # nested tuple
)
print(mixed[4][0]) # 1 (access list inside tuple)
# Tuples can have duplicate values
nums = (1, 2, 2, 3, 3, 3, 4)
print(nums) # (1, 2, 2, 3, 3, 3, 4)
print(nums.count(3)) # 3 (counts duplicates)
# Tuples can be used as dictionary keys!
point = (10, 20)
locations = {point: "Delhi"} # ✅ Valid
# But if tuple contains mutable items, it becomes unhashable
# invalid = ([1,2], 3) # ❌ TypeError: unhashable type: 'list'
import sys
my_list = [1, 2, 3, 4, 5]
my_tuple = (1, 2, 3, 4, 5)
list_size = sys.getsizeof(my_list) # ~120 bytes
tuple_size = sys.getsizeof(my_tuple) # ~80 bytes
print(f"List size: {list_size} bytes")
print(f"Tuple size: {tuple_size} bytes") # Tuple uses LESS memory!
1️⃣ Parentheses () (Most Common)
# Empty tuple
empty = ()
print(empty) # ()
# Tuple with items
fruits = ("apple", "banana", "mango")
numbers = (1, 2, 3, 4, 5)
# Single-element tuple (REQUIRES comma!)
single = (5,) # ✅ Correct - tuple with one element
not_tuple = (5) # ❌ This is just an integer (5)
print(type(single)) #
print(type(not_tuple)) #
2️⃣ Without Parentheses (Tuple Packing)
# Python creates tuple automatically when using commas
fruits = "apple", "banana", "mango"
print(fruits) # ('apple', 'banana', 'mango')
print(type(fruits)) #
# Even without parentheses, it's still a tuple
point = 10, 20
print(point) # (10, 20)
3️⃣ Using tuple() Constructor
# From list
my_tuple = tuple([1, 2, 3, 4])
print(my_tuple) # (1, 2, 3, 4)
# From string (each character becomes element)
char_tuple = tuple("hello")
print(char_tuple) # ('h', 'e', 'l', 'l', 'o')
# From range
range_tuple = tuple(range(1, 6))
print(range_tuple) # (1, 2, 3, 4, 5)
# From set
set_tuple = tuple({1, 2, 3})
print(set_tuple) # (1, 2, 3) (order may vary)
# Empty tuple
empty = tuple() # ()
4️⃣ Using Generator Expression
# Generator expression (note: parentheses, not brackets)
squares = tuple(x**2 for x in range(1, 6))
print(squares) # (1, 4, 9, 16, 25)
# With condition
even_squares = tuple(x**2 for x in range(1, 11) if x % 2 == 0)
print(even_squares) # (4, 16, 36, 64, 100)
5️⃣ Nested Tuples
# 2D Tuple (matrix)
matrix = (
(1, 2, 3),
(4, 5, 6),
(7, 8, 9)
)
print(matrix[1][1]) # 5
# 3D Tuple
cube = (
((1,2), (3,4)),
((5,6), (7,8))
)
print(cube[1][0][1]) # 6
6️⃣ From CSV/String Split
# Split string into tuple
data = "1,2,3,4,5"
tuple_data = tuple(data.split(','))
print(tuple_data) # ('1', '2', '3', '4', '5')
# Convert to numbers
numbers = tuple(int(x) for x in data.split(','))
print(numbers) # (1, 2, 3, 4, 5)
(5,) is a tuple, (5) is just an integer.
✅ Positive Indexing (0-based)
fruits = ("apple", "banana", "mango", "orange", "grape")
print(fruits[0]) # apple
print(fruits[2]) # mango
print(fruits[4]) # grape
# IndexError if out of range
# print(fruits[10]) # ❌ IndexError
✅ Negative Indexing
fruits = ("apple", "banana", "mango", "orange", "grape")
# negative: -5 -4 -3 -2 -1
print(fruits[-1]) # grape (last element)
print(fruits[-3]) # mango
print(fruits[-5]) # apple (first element)
✂️ Slicing Tuples
fruits = ("apple", "banana", "mango", "orange", "grape")
# Get slice (returns NEW tuple)
print(fruits[1:4]) # ('banana', 'mango', 'orange')
print(fruits[:3]) # ('apple', 'banana', 'mango')
print(fruits[2:]) # ('mango', 'orange', 'grape')
print(fruits[-3:]) # ('mango', 'orange', 'grape')
print(fruits[::-1]) # ('grape', 'orange', 'mango', 'banana', 'apple')
# Slicing never raises IndexError (returns empty if out of range)
print(fruits[10:20]) # () empty tuple
📊 Visual Index Map
Tuple: ("apple", "banana", "mango", "orange", "grape")
Index: 0 1 2 3 4
Negative: -5 -4 -3 -2 -1
Access: fruits[2] = "mango"
fruits[-2] = "orange"
fruits[1:4] = ("banana", "mango", "orange")
🛠️ 12.2 Tuple Methods & Operations – Complete Reference
Since tuples are immutable, they have only two built-in methods. However, they support many operations that don't modify the tuple.
| Method/Operation | Description | Example | Result |
|---|---|---|---|
count(x) |
Returns number of occurrences of x | (1,2,2,3).count(2) |
2 |
index(x[, start[, end]]) |
Returns first index of x (raises ValueError if not found) | (10,20,30).index(20) |
1 |
+ (concatenation) |
Joins two tuples | (1,2) + (3,4) |
(1,2,3,4) |
* (repetition) |
Repeats tuple n times | (1,2) * 3 |
(1,2,1,2,1,2) |
in operator |
Checks if element exists | 2 in (1,2,3) |
True |
not in operator |
Checks if element doesn't exist | 5 not in (1,2,3) |
True |
len() |
Returns length of tuple | len((1,2,3)) |
3 |
min() |
Returns smallest element | min((5,2,8,1)) |
1 |
max() |
Returns largest element | max((5,2,8,1)) |
8 |
sum() |
Returns sum of elements (numeric only) | sum((1,2,3,4)) |
10 |
sorted() |
Returns sorted list (tuple remains unchanged) | sorted((3,1,4,2)) |
[1,2,3,4] |
tuple() |
Converts iterable to tuple | tuple([1,2,3]) |
(1,2,3) |
📝 Detailed Examples
1️⃣ count() Method
nums = (1, 2, 2, 3, 3, 3, 4, 4, 4, 4)
print(nums.count(1)) # 1
print(nums.count(2)) # 2
print(nums.count(3)) # 3
print(nums.count(4)) # 4
print(nums.count(5)) # 0 (not found)
# Practical: Find most frequent element
most_frequent = max(set(nums), key=nums.count)
print(most_frequent) # 4
2️⃣ index() Method
fruits = ("apple", "banana", "mango", "banana", "orange")
# Find first occurrence
print(fruits.index("banana")) # 1
# Find with start parameter
print(fruits.index("banana", 2)) # 3 (start from index 2)
# Find within slice
# print(fruits.index("banana", 2, 4)) # Search between indices 2-4
# Error handling
try:
pos = fruits.index("grape")
except ValueError:
print("Item not found")
3️⃣ Concatenation +
t1 = (1, 2, 3)
t2 = (4, 5, 6)
# Creates NEW tuple
combined = t1 + t2
print(combined) # (1, 2, 3, 4, 5, 6)
# Original tuples unchanged
print(t1) # (1, 2, 3)
print(t2) # (4, 5, 6)
# Multiple concatenation
result = (1,2) + (3,4) + (5,6)
print(result) # (1, 2, 3, 4, 5, 6)
4️⃣ Repetition *
zeros = (0,) * 5
print(zeros) # (0, 0, 0, 0, 0)
pattern = (1, 2) * 3
print(pattern) # (1, 2, 1, 2, 1, 2)
# For nested tuples - CAUTION!
nested = ((0,) * 3) * 2 # Careful with references
print(nested) # ((0,0,0), (0,0,0))
5️⃣ Membership Testing
colors = ("red", "green", "blue", "yellow")
print("red" in colors) # True
print("black" in colors) # False
print("purple" not in colors) # True
# Practical usage
if "green" in colors:
print("Green is available!")
6️⃣ Built-in Functions
nums = (10, 5, 8, 3, 12, 7)
print(len(nums)) # 6
print(min(nums)) # 3
print(max(nums)) # 12
print(sum(nums)) # 45
# sorted() returns a list
sorted_list = sorted(nums)
print(sorted_list) # [3, 5, 7, 8, 10, 12]
print(nums) # (10, 5, 8, 3, 12, 7) (unchanged)
# any() and all()
print(any(x > 10 for x in nums)) # True (12 > 10)
print(all(x > 0 for x in nums)) # True (all positive)
📦 12.3 Tuple Packing & Unpacking – Complete Guide
📦 Tuple Packing
Packing is when you combine multiple values into a single tuple.
# Implicit packing (using commas)
person = "John", 25, "Developer"
print(person) # ('John', 25, 'Developer')
print(type(person)) #
# Explicit packing (using parentheses)
coordinates = (10, 20, 30)
print(coordinates) # (10, 20, 30)
# Packing different types
student = ("Amit", 101, 85.5, True)
print(student) # ('Amit', 101, 85.5, True)
📤 Tuple Unpacking
Unpacking is extracting tuple values into individual variables.
person = ("John", 25, "Developer")
# Unpack into variables
name, age, profession = person
print(name) # John
print(age) # 25
print(profession) # Developer
# Number of variables must match tuple length
# a, b = (1, 2, 3) # ❌ ValueError: too many values to unpack
✨ Extended Unpacking (Python 3+)
numbers = (1, 2, 3, 4, 5)
# Use * to collect remaining items
first, *rest = numbers
print(first) # 1
print(rest) # [2, 3, 4, 5]
*begin, last = numbers
print(begin) # [1, 2, 3, 4]
print(last) # 5
first, *middle, last = numbers
print(first) # 1
print(middle) # [2, 3, 4]
print(last) # 5
# Works with any iterable
first, second, *_ = numbers # Ignore the rest
🔄 Swapping Variables
# Traditional way (needs temporary variable)
a = 5
b = 10
temp = a
a = b
b = temp
# Python way using tuple packing/unpacking
a = 5
b = 10
a, b = b, a # Magic! 👇
# Right side: (b, a) creates tuple (10, 5)
# Left side: unpacks into a and b
print(a) # 10
print(b) # 5
# Multiple swaps
x, y, z = 1, 2, 3
x, y, z = z, x, y
print(x, y, z) # 3 1 2
🎯 Function Return Values
def get_min_max(numbers):
"""Return both minimum and maximum"""
return min(numbers), max(numbers) # Returns tuple
data = [5, 2, 8, 1, 9, 3]
result = get_min_max(data)
print(result) # (1, 9)
# Unpack directly
minimum, maximum = get_min_max(data)
print(f"Min: {minimum}, Max: {maximum}")
def get_student_info():
return "Amit", 101, 85.5 # Tuple packing
name, roll, percentage = get_student_info()
⚠️ Common Pitfalls
# Pitfall 1: Mismatched unpacking
# a, b = (1, 2, 3) # ValueError: too many values to unpack
# Pitfall 2: Forgetting parentheses in nested unpacking
nested = (1, (2, 3), 4)
# a, b, c = nested # b becomes (2,3), not unpacked
a, (b, c), d = nested # Correct! b=2, c=3
print(a, b, c, d) # 1 2 3 4
# Pitfall 3: Unpacking with _ for unused values
name, _, city = ("Amit", 25, "Delhi")
print(name) # Amit
print(city) # Delhi
# _ is convention for "ignore this value"
⚖️ 12.4 Tuple vs List – Complete Comparison
| Feature | List | Tuple |
|---|---|---|
| Mutability | ✅ Mutable (can change) | ❌ Immutable (cannot change) |
| Syntax | [ ] square brackets |
( ) parentheses |
| Speed | Slower (due to overhead for modifications) | Faster (optimized for fixed data) |
| Memory Usage | Higher (extra space for modifications) | Lower (more compact) |
| Methods | Many (append, insert, remove, etc.) | Only 2 (count, index) |
| Hashable | ❌ Cannot be dictionary key | ✅ Can be dictionary key (if elements hashable) |
| Use Case | Data that changes frequently | Fixed data, dictionary keys, function returns |
| Modification Methods | append(), extend(), insert(), remove(), pop() | None (immutable) |
| Creation | [1, 2, 3] or list() |
(1, 2, 3) or tuple() |
| Single Element | [5] – no comma needed |
(5,) – comma REQUIRED |
| Data Integrity | Can be accidentally modified | Safe from accidental changes |
📊 Performance Comparison
⚡ Creation Speed
import timeit
# List creation
list_time = timeit.timeit('[1,2,3,4,5]', number=1000000)
# Tuple creation
tuple_time = timeit.timeit('(1,2,3,4,5)', number=1000000)
print(f"List creation: {list_time:.4f}s")
print(f"Tuple creation: {tuple_time:.4f}s")
# Tuples are slightly faster to create
📈 Access Speed
# Access speed is nearly identical
import timeit
list_access = timeit.timeit('x = [1,2,3,4,5][2]', number=1000000)
tuple_access = timeit.timeit('x = (1,2,3,4,5)[2]', number=1000000)
print(f"List access: {list_access:.4f}s")
print(f"Tuple access: {tuple_access:.4f}s")
# Both are O(1) and very fast
💾 Memory Comparison
import sys
my_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
my_tuple = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
list_size = sys.getsizeof(my_list)
tuple_size = sys.getsizeof(my_tuple)
print(f"List size: {list_size} bytes")
print(f"Tuple size: {tuple_size} bytes")
print(f"Tuple uses {((list_size - tuple_size)/list_size)*100:.1f}% less memory")
🔑 As Dictionary Keys
# Tuples can be dictionary keys
locations = {
(28.6139, 77.2090): "Delhi",
(19.0760, 72.8777): "Mumbai",
(13.0827, 80.2707): "Chennai"
}
print(locations[(28.6139, 77.2090)]) # Delhi
# Lists cannot be keys
# invalid = {[1,2]: "value"} # TypeError!
# Tuples with mutable elements cannot be keys
# invalid = {(1, [2,3]): "value"} # TypeError!
- Use list when: data changes, you need append/insert/remove
- Use tuple when: data is fixed, need dictionary keys, want protection from changes
- Use tuple for: coordinates, RGB values, days of week, function returns
- Use list for: shopping lists, dynamic data, sequences that grow/shrink
💼 12.5 When to Use Tuples – Real-World Applications
📍 1. Geographic Coordinates
# Coordinates are fixed and shouldn't change
delhi = (28.6139, 77.2090)
mumbai = (19.0760, 72.8777)
chennai = (13.0827, 80.2707)
cities = {
delhi: "New Delhi",
mumbai: "Mumbai",
chennai: "Chennai"
}
def distance(coord1, coord2):
"""Calculate distance between two coordinates"""
lat1, lon1 = coord1
lat2, lon2 = coord2
# Simple Euclidean distance (example)
return ((lat2 - lat1)**2 + (lon2 - lon1)**2)**0.5
print(f"Distance: {distance(delhi, mumbai):.2f} degrees")
🎨 2. RGB Color Values
# Colors are constant values
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
color_palette = {
RED: "Crimson",
GREEN: "Lime",
BLUE: "Azure",
WHITE: "Pure White",
BLACK: "Pure Black"
}
def blend_colors(color1, color2):
"""Average two colors"""
return tuple((c1 + c2) // 2 for c1, c2 in zip(color1, color2))
purple = blend_colors(RED, BLUE)
print(f"Red + Blue = {purple}") # (127, 0, 127)
📅 3. Days of Week / Months
# Fixed data that never changes
DAYS = ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")
MONTHS = ("January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December")
def get_day_name(day_number):
"""Convert 0-6 to day name"""
if 0 <= day_number < 7:
return DAYS[day_number]
return "Invalid day"
print(get_day_name(0)) # Monday
print(get_day_name(6)) # Sunday
# Check if weekend
def is_weekend(day_name):
return day_name in ("Saturday", "Sunday")
📊 4. Database Records
# Database rows often returned as tuples
students = [
(101, "Amit", 21, "Computer Science"),
(102, "Neha", 20, "Mathematics"),
(103, "Raj", 22, "Physics")
]
# Tuples are immutable, so records can't be accidentally modified
for roll, name, age, dept in students:
print(f"Roll: {roll}, Name: {name}, Age: {age}, Dept: {dept}")
# Create lookup dictionary
student_by_id = {record[0]: record for record in students}
print(student_by_id[102]) # (102, 'Neha', 20, 'Mathematics')
⚙️ 5. Configuration Constants
# Application settings that shouldn't change
DATABASE_CONFIG = ("localhost", 3306, "myapp", "admin", "password")
API_ENDPOINTS = ("/users", "/products", "/orders")
SUPPORTED_LANGUAGES = ("en", "hi", "fr", "es")
host, port, db_name, user, pwd = DATABASE_CONFIG
print(f"Connecting to {host}:{port}/{db_name}")
# Version info as tuple (major, minor, patch)
VERSION = (1, 5, 2)
def check_version_compatibility(required_version):
return VERSION >= required_version
print(check_version_compatibility((1, 5, 0))) # True
🧮 6. Matrix Dimensions
# Matrix size is fixed
MATRIX_SIZE = (3, 3) # 3x3 matrix
def create_identity_matrix(size):
"""Create identity matrix of given size"""
rows, cols = size
return [[1 if i == j else 0 for j in range(cols)]
for i in range(rows)]
identity = create_identity_matrix(MATRIX_SIZE)
for row in identity:
print(row)
# [1, 0, 0]
# [0, 1, 0]
# [0, 0, 1]
# Image dimensions
image_size = (1920, 1080) # width, height
aspect_ratio = image_size[0] / image_size[1]
print(f"16:9? {abs(aspect_ratio - 16/9) < 0.01}")
🔄 7. Function Return Multiple Values
def divide_and_remainder(a, b):
"""Returns quotient and remainder as tuple"""
return a // b, a % b
quotient, remainder = divide_and_remainder(17, 5)
print(f"17 ÷ 5 = {quotient} remainder {remainder}")
def analyze_numbers(numbers):
"""Returns multiple statistics as tuple"""
return (
min(numbers),
max(numbers),
sum(numbers) / len(numbers),
len(numbers)
)
minimum, maximum, average, count = analyze_numbers([10, 20, 30, 40, 50])
print(f"Min: {minimum}, Max: {maximum}, Avg: {average}, Count: {count}")
🗃️ 8. Dictionary Keys (Composite Keys)
# Use tuples for composite keys
phonebook = {
("John", "Doe"): "555-1234",
("Jane", "Smith"): "555-5678",
("Bob", "Johnson"): "555-9012"
}
# Lookup by first and last name
def find_phone(first, last):
return phonebook.get((first, last), "Not found")
print(find_phone("John", "Doe")) # 555-1234
# Student grades by (subject, roll_no)
grades = {
("Math", 101): 85,
("Math", 102): 92,
("Science", 101): 78,
("Science", 102): 88
}
def get_grade(subject, roll):
return grades.get((subject, roll), "No grade")
🧵 9. Thread-Safe Data
import threading
# Tuples are immutable and thread-safe
SHARED_CONFIG = ("production", 8080, True)
def worker():
# Multiple threads can safely read without locks
env, port, debug = SHARED_CONFIG
print(f"Environment: {env}, Port: {port}")
# Create multiple threads accessing the same tuple
threads = []
for i in range(5):
t = threading.Thread(target=worker)
threads.append(t)
t.start()
for t in threads:
t.join()
📈 10. Named Tuples (Advanced)
from collections import namedtuple
# Create tuple-like classes with named fields
Point = namedtuple('Point', ['x', 'y'])
Student = namedtuple('Student', ['name', 'roll', 'marks'])
# Create instances (still immutable!)
p1 = Point(10, 20)
s1 = Student('Amit', 101, 85)
# Access by name or index
print(p1.x, p1[0]) # 10 10
print(s1.name, s1[0]) # Amit Amit
# Great for self-documenting code
def calculate_distance(p1, p2):
return ((p2.x - p1.x)**2 + (p2.y - p1.y)**2)**0.5
p1 = Point(0, 0)
p2 = Point(3, 4)
print(calculate_distance(p1, p2)) # 5.0
Many beginners wonder: "If there's list comprehension, is there tuple comprehension?"
❌ What looks like tuple comprehension is actually a generator!
# This is NOT a tuple comprehension
not_tuple = (x**2 for x in range(5))
print(type(not_tuple)) #
# It's a generator expression
gen = (x**2 for x in range(5))
print(gen) #
# To create a tuple from generator:
tuple_gen = tuple(x**2 for x in range(5))
print(tuple_gen) # (0, 1, 4, 9, 16)
✅ Correct ways to create tuple from comprehension:
# Method 1: Use tuple() with generator
squares = tuple(x**2 for x in range(5))
# Method 2: Use tuple() with list comprehension
squares = tuple([x**2 for x in range(5)])
# Method 3: Unpacking (Python 3.5+)
squares = (*(x**2 for x in range(5)),)
print(squares) # (0, 1, 4, 9, 16)
# Generator expressions are memory efficient
# for large sequences
big_tuple = tuple(x**2 for x in range(1000000))
() are used for both tuples and generator expressions. The difference is whether there's a for clause inside!
How do you create a tuple with a single element 5?
What is the output of (1,2,3) + (4,5)?
Can a tuple be used as a dictionary key?
What does (1,2,3)[1:2] return?
🏆 Challenge Problems
# Challenge 1: Swap variables without temporary variable
a, b = 5, 10
a, b = b, a
print(a, b) # 10 5
# Challenge 2: Create a function that returns min, max, and average
def stats(numbers):
return min(numbers), max(numbers), sum(numbers)/len(numbers)
min_val, max_val, avg = stats([1,2,3,4,5])
print(f"Min: {min_val}, Max: {max_val}, Avg: {avg}")
# Challenge 3: Convert list of pairs to dictionary using tuple unpacking
pairs = [(1, 'one'), (2, 'two'), (3, 'three')]
result = {k: v for k, v in pairs}
print(result) # {1: 'one', 2: 'two', 3: 'three'}
# Challenge 4: Flatten list of tuples
tuple_list = [(1,2), (3,4), (5,6)]
flattened = [item for tup in tuple_list for item in tup]
print(flattened) # [1, 2, 3, 4, 5, 6]
# Challenge 5: Find all pairs that sum to target
def find_pairs(nums, target):
seen = set()
pairs = []
for num in nums:
complement = target - num
if complement in seen:
pairs.append((complement, num))
seen.add(num)
return pairs
print(find_pairs([1,2,3,4,5], 6)) # [(1,5), (2,4)]
🎓 Module 12 : Python Tuple (Immutable Collection) Successfully Completed
You have successfully completed this module of Python for Cybersecurity.
Keep building your expertise step by step — Learn Next Module →
🗂️ Python Dictionary – The Complete Master Guide
📚 13.1 Dictionary Basics – The Complete Guide
A dictionary is an unordered, mutable collection of key-value pairs. Each key is unique and maps to a value. Think of it as a real-world dictionary:
📖 Real-World Analogy
- 📘 Dictionary Book: Word (key) → Definition (value)
- 📞 Phonebook: Name (key) → Phone Number (value)
- 🏷️ Price List: Product (key) → Price (value)
- 👤 Student Record: Roll Number (key) → Student Info (value)
🐍 Python Example
student = {
"name": "Amit", # key: "name", value: "Amit"
"age": 21, # key: "age", value: 21
"course": "Python" # key: "course", value: "Python"
}
🔑 Key Characteristics of Dictionaries
# If you use duplicate keys, last one wins
d = {"name": "Amit", "name": "Raj"}
print(d) # {'name': 'Raj'} (Amit is overwritten)
# Valid keys: strings, numbers, tuples
d = {
"name": "Amit", # string key
1: "one", # integer key
(1,2): "tuple" # tuple key
}
# Invalid: lists, dictionaries as keys
# d[["list"]] = "error" # TypeError!
d = {
"name": "Amit", # string
"age": 21, # integer
"marks": [85, 90, 78], # list
"address": { # nested dictionary
"city": "Delhi",
"pin": 110001
},
"passed": True # boolean
}
student = {"name": "Amit", "age": 21}
# Change existing value
student["age"] = 22
# Add new key-value pair
student["city"] = "Mumbai"
print(student)
# {'name': 'Amit', 'age': 22, 'city': 'Mumbai'}
# In Python 3.7+, dictionaries preserve insertion order
d = {"b": 2, "a": 1, "c": 3}
print(d) # {'b': 2, 'a': 1, 'c': 3} (order preserved)
# Dictionaries use hash tables for lightning-fast access
# Accessing by key is extremely fast even with millions of items
student = {"name": "Amit", "age": 21}
print(student["name"]) # O(1) operation
1️⃣ Curly Braces {} (Most Common)
# Empty dictionary
empty = {}
# Dictionary with items
student = {
"name": "Amit",
"age": 21,
"course": "Python"
}
2️⃣ dict() Constructor
# From keyword arguments
person = dict(name="Amit", age=21, city="Delhi")
# {'name': 'Amit', 'age': 21, 'city': 'Delhi'}
# From list of tuples
pairs = [("name", "Amit"), ("age", 21), ("city", "Delhi")]
person = dict(pairs)
# From zip of two lists
keys = ["name", "age", "city"]
values = ["Amit", 21, "Delhi"]
person = dict(zip(keys, values))
3️⃣ Dictionary Comprehension
# Squares dictionary
squares = {x: x**2 for x in range(1, 6)}
# {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
# Even squares only
even_squares = {x: x**2 for x in range(1, 11) if x % 2 == 0}
# {2: 4, 4: 16, 6: 36, 8: 64, 10: 100}
# From two lists with condition
names = ["Amit", "Neha", "Raj"]
scores = [85, 92, 78]
passed = {name: score for name, score in zip(names, scores) if score >= 80}
# {'Amit': 85, 'Neha': 92}
4️⃣ fromkeys() Method
# Create dictionary with default values
keys = ["name", "age", "city"]
default_dict = dict.fromkeys(keys, "unknown")
# {'name': 'unknown', 'age': 'unknown', 'city': 'unknown'}
# Default None if no default provided
default_none = dict.fromkeys(keys)
# {'name': None, 'age': None, 'city': None}
5️⃣ Using setdefault()
# Create key with default if not exists
d = {}
d.setdefault("name", "Amit") # Adds name: Amit
d.setdefault("name", "Raj") # Does nothing (key exists)
print(d) # {'name': 'Amit'}
6️⃣ Nested Dictionary Creation
# Using nested braces
students = {
"101": {"name": "Amit", "age": 21},
"102": {"name": "Neha", "age": 20}
}
# Using comprehension for nested structure
matrix = {i: {j: i*j for j in range(1, 4)} for i in range(1, 4)}
# {1: {1:1, 2:2, 3:3}, 2: {1:2, 2:4, 3:6}, 3: {1:3, 2:6, 3:9}}
1️⃣ Square Brackets []
student = {"name": "Amit", "age": 21}
print(student["name"]) # Amit
print(student["age"]) # 21
# What if key doesn't exist?
# print(student["city"]) # KeyError! (crashes)
2️⃣ get() Method (Safe Access)
# Returns None if key doesn't exist
print(student.get("city")) # None
print(student.get("name")) # Amit
# Provide default value
print(student.get("city", "Not Found")) # "Not Found"
# Perfect for safe lookups
age = student.get("age", 0) # Returns 21
city = student.get("city", "Unknown") # Returns "Unknown"
3️⃣ setdefault() – Get or Set Default
student = {"name": "Amit"}
# If key exists, returns value
age = student.setdefault("age", 25) # Adds age:25, returns 25
print(student) # {'name': 'Amit', 'age': 25}
# If key exists, returns existing value
age_again = student.setdefault("age", 30) # Returns 25 (existing)
print(student) # {'name': 'Amit', 'age': 25} (unchanged)
4️⃣ Checking if Key Exists
student = {"name": "Amit", "age": 21}
# Using 'in' operator
if "name" in student:
print("Name exists!")
if "city" not in student:
print("City not found")
5️⃣ Accessing All Keys/Values/Items
student = {"name": "Amit", "age": 21, "city": "Delhi"}
# Get all keys
keys = student.keys()
print(keys) # dict_keys(['name', 'age', 'city'])
# Get all values
values = student.values()
print(values) # dict_values(['Amit', 21, 'Delhi'])
# Get all key-value pairs
items = student.items()
print(items) # dict_items([('name', 'Amit'), ('age', 21), ('city', 'Delhi')])
# These are view objects (dynamic)
student["country"] = "India"
print(keys) # dict_keys(['name', 'age', 'city', 'country']) - automatically updated!
get() when you're not sure if a key exists. Square brackets are faster but will crash if key is missing.
🛠️ 13.2 Complete Dictionary Methods Reference
| Method | Description | Example | Result |
|---|---|---|---|
get(key[, default]) |
Returns value for key (or default) | d.get("name", "Unknown") |
Value or "Unknown" |
keys() |
Returns view of all keys | d.keys() |
dict_keys(['a','b']) |
values() |
Returns view of all values | d.values() |
dict_values([1,2]) |
items() |
Returns view of key-value pairs | d.items() |
dict_items([('a',1)]) |
update([other]) |
Merges another dict (overwrites) | d.update({"b":3}) |
{'a':1, 'b':3} |
pop(key[, default]) |
Removes key and returns value | d.pop("a") |
1 (and removes 'a') |
popitem() |
Removes and returns last inserted | d.popitem() |
('b',2) |
setdefault(key[, default]) |
Returns value, sets default if missing | d.setdefault("c", 3) |
3 (adds 'c':3) |
clear() |
Removes all items | d.clear() |
{} |
copy() |
Returns shallow copy | d2 = d.copy() |
New dictionary |
fromkeys(seq[, value]) |
Creates new dict from keys | dict.fromkeys(['a','b'], 0) |
{'a':0,'b':0} |
📝 Detailed Examples for Each Method
1️⃣ get() – Safe Value Access
student = {"name": "Amit", "age": 21}
print(student.get("name")) # Amit
print(student.get("city")) # None
print(student.get("city", "N/A")) # N/A
# Useful in calculations
score = student.get("score", 0) + 10
print(score) # 10 (since score didn't exist)
2️⃣ keys(), values(), items()
d = {"a": 1, "b": 2, "c": 3}
# Convert to lists
keys_list = list(d.keys()) # ['a', 'b', 'c']
values_list = list(d.values()) # [1, 2, 3]
items_list = list(d.items()) # [('a',1), ('b',2), ('c',3)]
# Check membership
print("a" in d.keys()) # True
print(1 in d.values()) # True
print(("a",1) in d.items()) # True
3️⃣ update() – Merging Dictionaries
d1 = {"a": 1, "b": 2}
d2 = {"b": 3, "c": 4}
# Update d1 with d2
d1.update(d2)
print(d1) # {'a': 1, 'b': 3, 'c': 4} (b overwritten)
# Update with keyword arguments
d1.update(d=5, e=6)
print(d1) # {'a':1, 'b':3, 'c':4, 'd':5, 'e':6}
# Update with list of tuples
d1.update([("f", 7), ("g", 8)])
print(d1) # ... 'f':7, 'g':8
4️⃣ pop() and popitem()
d = {"a": 1, "b": 2, "c": 3}
# pop() removes and returns value
value = d.pop("b")
print(value) # 2
print(d) # {'a': 1, 'c': 3}
# pop with default (avoids KeyError)
value = d.pop("z", "Not found")
print(value) # "Not found"
# popitem() removes last inserted (Python 3.7+)
last = d.popitem()
print(last) # ('c', 3) (or whatever was last)
5️⃣ setdefault() – Get or Set
inventory = {"apple": 10, "banana": 5}
# If key exists, returns value
apples = inventory.setdefault("apple", 0)
print(apples) # 10
# If key doesn't exist, sets default and returns it
oranges = inventory.setdefault("orange", 0)
print(oranges) # 0
print(inventory) # {'apple':10, 'banana':5, 'orange':0}
# Great for counting/frequency
word_count = {}
for word in ["a", "b", "a", "c", "b", "a"]:
word_count[word] = word_count.setdefault(word, 0) + 1
print(word_count) # {'a':3, 'b':2, 'c':1}
6️⃣ copy() and clear()
original = {"a": 1, "b": [1, 2, 3]}
# Shallow copy
shallow = original.copy()
shallow["b"].append(4) # Modifies original's list too!
print(original) # {'a':1, 'b':[1,2,3,4]}
# Deep copy (for nested structures)
import copy
deep = copy.deepcopy(original)
deep["b"].append(5) # Original unchanged
print(original) # {'a':1, 'b':[1,2,3,4]}
print(deep) # {'a':1, 'b':[1,2,3,4,5]}
# clear() removes all items
original.clear()
print(original) # {}
🥪 13.3 Nested Dictionaries – Dictionary Inside Dictionary
A nested dictionary is a dictionary where values can themselves be dictionaries. This creates hierarchical data structures, perfect for representing real-world complex data.
📊 Visual Representation
students = {
"101": { # First student (key: roll number)
"name": "Amit",
"age": 21,
"marks": {
"math": 85,
"science": 90,
"english": 78
}
},
"102": { # Second student
"name": "Neha",
"age": 20,
"marks": {
"math": 92,
"science": 88,
"english": 95
}
}
}
🔍 Accessing Nested Values
# Get Amit's math marks
math_marks = students["101"]["marks"]["math"]
print(math_marks) # 85
# Get Neha's name
name = students["102"]["name"]
print(name) # Neha
# Safe access with multiple gets
math = students.get("101", {}).get("marks", {}).get("math", 0)
print(math) # 85 (safe even if keys missing)
✏️ Modifying Nested Values
# Update Amit's age
students["101"]["age"] = 22
# Add new subject for Neha
students["102"]["marks"]["computer"] = 95
# Add new student
students["103"] = {
"name": "Raj",
"age": 22,
"marks": {}
}
print(students["103"]["name"]) # Raj
🔄 Looping Through Nested Dictionaries
# Loop through all students
for roll, info in students.items():
print(f"Roll: {roll}")
print(f" Name: {info['name']}")
print(f" Age: {info['age']}")
print(" Marks:")
for subject, mark in info['marks'].items():
print(f" {subject}: {mark}")
📝 Real-World JSON Example
# API Response Simulation
api_response = {
"status": "success",
"data": {
"users": [
{"id": 1, "name": "Amit", "email": "amit@test.com"},
{"id": 2, "name": "Neha", "email": "neha@test.com"}
],
"total": 2,
"page": 1
},
"message": "Users retrieved"
}
# Extract first user's email
email = api_response["data"]["users"][0]["email"]
print(email) # amit@test.com
json module to convert between JSON and Python dictionaries seamlessly.
1️⃣ Manual Creation
company = {
"engineering": {
"manager": "Rahul",
"employees": ["Amit", "Neha"]
},
"sales": {
"manager": "Priya",
"employees": ["Raj", "Simran"]
}
}
2️⃣ Using Loops
employees = {}
for dept in ["eng", "sales", "hr"]:
employees[dept] = {
"count": 0,
"names": []
}
# {'eng': {'count':0, 'names':[]}, ...}
3️⃣ Dictionary Comprehension
# Create multiplication table as nested dict
table = {i: {j: i*j for j in range(1, 4)} for i in range(1, 4)}
# {1: {1:1,2:2,3:3}, 2: {1:2,2:4,3:6}, 3: {1:3,2:6,3:9}}
4️⃣ From CSV Data
csv_data = """name,age,city
Amit,21,Delhi
Neha,20,Mumbai
Raj,22,Chennai"""
rows = csv_data.split('\n')[1:]
students = {}
for i, row in enumerate(rows, start=1):
name, age, city = row.split(',')
students[f"S{i:03d}"] = {
"name": name,
"age": int(age),
"city": city
}
🔄 13.4 Looping Through Dictionaries – 10 Methods
1️⃣ Loop Through Keys (Default)
student = {"name": "Amit", "age": 21, "city": "Delhi"}
for key in student:
print(key, ":", student[key])
# Output:
# name : Amit
# age : 21
# city : Delhi
2️⃣ Loop Through Keys (Explicit)
for key in student.keys():
print(key)
3️⃣ Loop Through Values
for value in student.values():
print(value)
# Useful when you don't need keys
total_age = sum(student.values()) # If all values are numbers
4️⃣ Loop Through Key-Value Pairs (Best!)
for key, value in student.items():
print(f"{key}: {value}")
# Most Pythonic and efficient way
5️⃣ Loop with Condition
scores = {"Amit": 85, "Neha": 92, "Raj": 78, "Priya": 88}
# Get students with score > 80
for name, score in scores.items():
if score > 80:
print(f"{name} passed with {score}")
6️⃣ Loop While Modifying (Safe Way)
# Create a copy of items to avoid modification issues
for key, value in list(scores.items()):
if value < 80:
scores.pop(key) # Safe to modify when iterating over list copy
print(scores) # {'Amit':85, 'Neha':92, 'Priya':88}
7️⃣ Nested Dictionary Looping
students = {
"101": {"name": "Amit", "age": 21},
"102": {"name": "Neha", "age": 20}
}
for roll, info in students.items():
print(f"Roll: {roll}")
for key, value in info.items():
print(f" {key}: {value}")
8️⃣ Using enumerate with Dictionaries
for index, (key, value) in enumerate(student.items()):
print(f"{index}. {key}: {value}")
# Output:
# 0. name: Amit
# 1. age: 21
# 2. city: Delhi
9️⃣ Loop with Sorted Keys
d = {"banana": 3, "apple": 1, "cherry": 2}
for key in sorted(d.keys()):
print(f"{key}: {d[key]}")
# apple: 1
# banana: 3
# cherry: 2
🔟 Loop with Dictionary Comprehension
# Create new dict from existing
squares = {x: x**2 for x in range(1, 6)}
# {1:1, 2:4, 3:9, 4:16, 5:25}
# Filter while creating
even_squares = {x: x**2 for x in range(1, 11) if x % 2 == 0}
# {2:4, 4:16, 6:36, 8:64, 10:100}
💼 13.5 Real-World Use Cases – JSON, APIs, Configurations
📊 1. Word Frequency Counter
text = "the quick brown fox jumps over the lazy dog the fox"
words = text.split()
freq = {}
for word in words:
freq[word] = freq.get(word, 0) + 1
print(freq)
# {'the': 3, 'quick': 1, 'brown': 1, 'fox': 2, ...}
# Find most common word
most_common = max(freq, key=freq.get)
print(f"Most common: {most_common} ({freq[most_common]} times)")
🌐 2. API Response Handling
import json
# Simulated API response
api_response = '''
{
"status": "success",
"data": {
"users": [
{"id": 1, "name": "Amit", "email": "amit@test.com"},
{"id": 2, "name": "Neha", "email": "neha@test.com"}
],
"total": 2
}
}'''
data = json.loads(api_response)
# Extract user emails
emails = [user["email"] for user in data["data"]["users"]]
print(emails) # ['amit@test.com', 'neha@test.com']
⚙️ 3. Configuration Settings
config = {
"database": {
"host": "localhost",
"port": 3306,
"username": "admin",
"password": "secret",
"database": "myapp"
},
"app": {
"name": "My Application",
"version": "1.0.0",
"debug": True,
"theme": {
"primary": "#007bff",
"secondary": "#6c757d"
}
}
}
# Access nested config
host = config["database"]["host"]
port = config["database"]["port"]
primary_color = config["app"]["theme"]["primary"]
📝 4. CSV to Dictionary
import csv
# Read CSV file into list of dictionaries
def csv_to_dict(filename):
with open(filename, 'r') as file:
reader = csv.DictReader(file)
return [row for row in reader]
# Example CSV content:
# name,age,city
# Amit,21,Delhi
# Neha,20,Mumbai
# Result: [{'name':'Amit','age':'21','city':'Delhi'}, ...]
📦 5. Inventory Management
inventory = {
"apple": {"price": 50, "stock": 100},
"banana": {"price": 30, "stock": 150},
"orange": {"price": 40, "stock": 75},
"mango": {"price": 80, "stock": 50}
}
def update_stock(item, quantity):
if item in inventory:
inventory[item]["stock"] -= quantity
return f"Remaining {item}: {inventory[item]['stock']}"
return "Item not found"
def total_value():
return sum(item["price"] * item["stock"]
for item in inventory.values())
print(f"Total inventory value: ₹{total_value()}")
🧮 6. Grouping Data
students = [
("Amit", "A", 85),
("Neha", "B", 92),
("Raj", "A", 78),
("Priya", "C", 88),
("Simran", "B", 95)
]
# Group by grade
by_grade = {}
for name, grade, score in students:
if grade not in by_grade:
by_grade[grade] = []
by_grade[grade].append({"name": name, "score": score})
print(by_grade["A"]) # Students with grade A
🎮 7. Game Character Stats
character = {
"name": "Warrior",
"level": 10,
"health": 100,
"mana": 50,
"stats": {
"strength": 85,
"agility": 60,
"intelligence": 40
},
"inventory": {
"weapon": {"name": "Sword", "damage": 25},
"armor": {"name": "Plate Mail", "defense": 40},
"potions": ["health", "mana", "strength"]
}
}
def attack(character):
base_damage = character["stats"]["strength"] // 10
weapon_damage = character["inventory"]["weapon"]["damage"]
return base_damage + weapon_damage
print(f"Attack power: {attack(character)}")
🗃️ 8. Cache/Memoization
# Fibonacci with caching
fib_cache = {}
def fibonacci(n):
if n in fib_cache:
return fib_cache[n]
if n <= 1:
result = n
else:
result = fibonacci(n-1) + fibonacci(n-2)
fib_cache[n] = result
return result
# Calculate fibonacci(100) efficiently
print(fibonacci(100))
📊 9. Database Record Representation
# Simulating database records
users = [
{"id": 1, "username": "amit123", "email": "amit@test.com", "active": True},
{"id": 2, "username": "neha456", "email": "neha@test.com", "active": False},
{"id": 3, "username": "raj789", "email": "raj@test.com", "active": True}
]
# Filter active users
active_users = [user for user in users if user["active"]]
# Create username lookup (for O(1) access)
username_lookup = {user["username"]: user for user in users}
print(username_lookup["amit123"]["email"]) # amit@test.com
🌍 10. Multi-language Support
translations = {
"en": {
"welcome": "Welcome",
"goodbye": "Goodbye",
"thank_you": "Thank you"
},
"hi": {
"welcome": "स्वागत है",
"goodbye": "अलविदा",
"thank_you": "धन्यवाद"
},
"fr": {
"welcome": "Bienvenue",
"goodbye": "Au revoir",
"thank_you": "Merci"
}
}
def translate(key, language="en"):
return translations.get(language, {}).get(key, key)
print(translate("welcome", "hi")) # स्वागत है
print(translate("thank_you", "fr")) # Merci
| Feature | Dictionary | List | Tuple | Set |
|---|---|---|---|---|
| Ordered | ✅ (Python 3.7+) | ✅ | ✅ | ❌ |
| Mutable | ✅ | ✅ | ❌ | ✅ |
| Indexed by | Keys | Position | Position | N/A |
| Duplicates allowed | Keys: ❌, Values: ✅ | ✅ | ✅ | ❌ |
| Lookup speed | O(1) average | O(n) | O(n) | O(1) |
| Use case | Key-value data | Ordered sequences | Fixed data | Unique items |
- Need fast lookups by key (like a phonebook)
- Working with structured/JSON data
- Counting frequencies of items
- Grouping and categorizing data
- Configuration settings
- Caching/memoization
✅ DO's
- Use
get()for safe access - Use
into check key existence - Use
items()for looping - Use dictionary comprehensions for clarity
- Use
setdefault()for counting
❌ DON'Ts
- Don't modify dict while iterating (use copy)
- Don't use mutable objects as keys
- Don't use
[]access when key might be missing - Don't create deep nested structures unnecessarily
# Performance comparison
import time
# Dictionary lookup vs list search
data_dict = {i: i**2 for i in range(1000000)}
data_list = [i**2 for i in range(1000000)]
# Dictionary lookup O(1)
start = time.time()
value = data_dict.get(999999)
dict_time = time.time() - start
# List search O(n)
start = time.time()
value = 999999**2 in data_list # This searches entire list!
list_time = time.time() - start
print(f"Dict lookup: {dict_time:.6f} seconds")
print(f"List search: {list_time:.6f} seconds")
# Dictionary is thousands of times faster!
Basic Examples
# Squares
squares = {x: x**2 for x in range(1, 6)}
# {1:1, 2:4, 3:9, 4:16, 5:25}
# Even squares only
even_squares = {x: x**2 for x in range(1, 11) if x % 2 == 0}
# {2:4, 4:16, 6:36, 8:64, 10:100}
# From two lists
names = ["Amit", "Neha", "Raj"]
ages = [21, 20, 22]
students = {name: age for name, age in zip(names, ages)}
# {'Amit':21, 'Neha':20, 'Raj':22}
With Conditions
# Filter by value
scores = {"Amit":85, "Neha":92, "Raj":78, "Priya":88}
passed = {name: score for name, score in scores.items() if score >= 80}
# {'Amit':85, 'Neha':92, 'Priya':88}
# Transform values
double_scores = {name: score*2 for name, score in scores.items()}
# {'Amit':170, 'Neha':184, 'Raj':156, 'Priya':176}
Nested Comprehension
# Create multiplication table
table = {i: {j: i*j for j in range(1, 4)} for i in range(1, 4)}
# {
# 1: {1:1, 2:2, 3:3},
# 2: {1:2, 2:4, 3:6},
# 3: {1:3, 2:6, 3:9}
# }
# Matrix transpose using comprehension
matrix = [[1,2,3], [4,5,6], [7,8,9]]
transpose = {i: {j: matrix[j][i] for j in range(3)} for i in range(3)}
Advanced Examples
# Invert dictionary (swap keys and values)
original = {"a": 1, "b": 2, "c": 3}
inverted = {value: key for key, value in original.items()}
# {1:'a', 2:'b', 3:'c'}
# Group by length
words = ["cat", "elephant", "dog", "butterfly", "ant"]
by_length = {len(word): [w for w in words if len(w) == len(word)]
for word in words}
# {3: ['cat','dog','ant'], 7: ['elephant'], 8: ['butterfly']}
How do you safely get a value from a dictionary without raising an error if key doesn't exist?
What will {"a":1, "b":2, "a":3} result in?
Which method returns all key-value pairs as tuples?
How to merge two dictionaries d1 and d2?
🏆 Challenge Problems
# Challenge 1: Count character frequency in a string
text = "hello world"
char_count = {char: text.count(char) for char in set(text)}
# {'h':1, 'e':1, 'l':3, 'o':2, ' ':1, 'w':1, 'r':1, 'd':1}
# Challenge 2: Find keys with maximum value
scores = {"Amit":85, "Neha":92, "Raj":78, "Priya":92}
max_score = max(scores.values())
top_students = [name for name, score in scores.items() if score == max_score]
# ['Neha', 'Priya']
# Challenge 3: Convert list to dictionary with index as key
items = ["apple", "banana", "cherry"]
indexed = {i: item for i, item in enumerate(items)}
# {0:'apple', 1:'banana', 2:'cherry'}
# Challenge 4: Group numbers by even/odd
numbers = [1,2,3,4,5,6,7,8,9,10]
grouped = {"even": [n for n in numbers if n%2==0],
"odd": [n for n in numbers if n%2!=0]}
# {'even':[2,4,6,8,10], 'odd':[1,3,5,7,9]}
🎓 Module 13 : Python Dictionary (Key-Value Storage) Successfully Completed
You have successfully completed this module of Python for Cybersecurity.
Keep building your expertise step by step — Learn Next Module →
📦 Python Arrays – The Complete Master Guide
📚 14.1 Introduction to Arrays – The Complete Guide
An array is a data structure that stores a collection of elements of the same type in contiguous memory locations. Python's built-in array module provides a space-efficient storage for basic data types like integers, floats, and characters.
📖 Real-World Analogy
- 🏭 Factory Assembly Line: All items are identical type
- 📦 Egg Carton: Only eggs, all same size
- 📊 Excel Column: All cells contain same data type
🐍 Python Array Example
from array import array
# Create integer array (type code 'i')
numbers = array('i', [10, 20, 30, 40, 50])
print(numbers) # array('i', [10, 20, 30, 40, 50])
print(type(numbers)) #
# Create float array (type code 'f')
floats = array('f', [1.5, 2.7, 3.14, 4.2])
print(floats) # array('f', [1.5, 2.7, 3.14, 4.2])
🔑 Key Characteristics of Arrays
from array import array
# All elements must be same type
numbers = array('i', [1, 2, 3, 4]) # ✅ All integers
# This will cause error:
# numbers = array('i', [1, 2, 3.14, 4]) # ❌ TypeError!
import sys
from array import array
# List of integers
list_int = [1, 2, 3, 4, 5]
list_size = sys.getsizeof(list_int)
# Array of integers
arr_int = array('i', [1, 2, 3, 4, 5])
arr_size = sys.getsizeof(arr_int)
print(f"List size: {list_size} bytes")
print(f"Array size: {arr_size} bytes")
# Array uses 30-40% less memory!
from array import array
import time
arr = array('i', range(1000000))
lst = list(range(1000000))
# Access speed test
start = time.time()
for i in range(100000):
x = arr[i]
arr_time = time.time() - start
start = time.time()
for i in range(100000):
x = lst[i]
lst_time = time.time() - start
print(f"Array access: {arr_time:.4f}s")
print(f"List access: {lst_time:.4f}s")
# Array is slightly faster
from array import array
arr = array('i', [10, 20, 30, 40, 50, 60])
print(arr[0]) # 10
print(arr[-1]) # 60
print(arr[1:4]) # array('i', [20, 30, 40])
print(arr[::-1]) # array('i', [60, 50, 40, 30, 20, 10])
# Works just like lists!
📋 Complete Type Codes Reference
| Type Code | C Type | Python Type | Size (bytes) | Example |
|---|---|---|---|---|
'b' | signed char | int | 1 | array('b', [-10, 20]) |
'B' | unsigned char | int | 1 | array('B', [10, 200]) |
'h' | signed short | int | 2 | array('h', [-1000, 5000]) |
'H' | unsigned short | int | 2 | array('H', [1000, 60000]) |
'i' | signed int | int | 4 | array('i', [-100000, 500000]) |
'I' | unsigned int | int | 4 | array('I', [1000, 4000000]) |
'l' | signed long | int | 8 | array('l', [-1000000, 5000000]) |
'L' | unsigned long | int | 8 | array('L', [1000000, 9000000]) |
'q' | signed long long | int | 8 | array('q', [-10**10, 10**10]) |
'Q' | unsigned long long | int | 8 | array('Q', [10**10, 10**11]) |
'f' | float | float | 4 | array('f', [1.5, 2.7]) |
'd' | double | float | 8 | array('d', [3.14159, 2.71828]) |
'u' | wchar_t | Unicode char | 2/4 | array('u', 'hello') |
1️⃣ From List
from array import array
# Create from existing list
numbers = array('i', [1, 2, 3, 4, 5])
print(numbers) # array('i', [1, 2, 3, 4, 5])
# Empty array
empty = array('i') # array('i')
2️⃣ From Tuple
from array import array
# Tuple works too
values = array('f', (1.5, 2.7, 3.14))
print(values) # array('f', [1.5, 2.7, 3.14])
3️⃣ From Range
from array import array
# Using range
numbers = array('i', range(1, 11))
print(numbers) # array('i', [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
# With step
evens = array('i', range(0, 21, 2))
print(evens) # array('i', [0, 2, 4, ..., 20])
4️⃣ From String (for 'u' type)
from array import array
# Character array
chars = array('u', 'hello')
print(chars) # array('u', 'h', 'e', 'l', 'l', 'o')
print(chars[0]) # h
5️⃣ Using Comprehension
from array import array
# List comprehension then convert
squares = array('i', [x**2 for x in range(1, 11)])
print(squares) # array('i', [1, 4, 9, 16, 25, 36, 49, 64, 81, 100])
# With condition
evens_squared = array('i', [x**2 for x in range(1, 11) if x % 2 == 0])
print(evens_squared) # array('i', [4, 16, 36, 64, 100])
6️⃣ From Bytes/File
from array import array
# Read from binary file
with open('data.bin', 'rb') as f:
data = array('i')
data.frombytes(f.read())
# Write to binary file
with open('output.bin', 'wb') as f:
data = array('i', [1, 2, 3, 4, 5])
f.write(data.tobytes())
7️⃣ Using fromlist()
from array import array
arr = array('i') # Empty array
arr.fromlist([1, 2, 3, 4, 5]) # Add from list
print(arr) # array('i', [1, 2, 3, 4, 5])
8️⃣ Using fromunicode()
from array import array
# For 'u' type arrays
chars = array('u')
chars.fromunicode("Python")
print(chars) # array('u', 'P', 'y', 't', 'h', 'o', 'n')
from array import array
arr = array('i', [10, 20, 30, 40, 50, 60, 70, 80, 90, 100])
# Indexing
print(arr[0]) # 10
print(arr[5]) # 60
print(arr[-1]) # 100
print(arr[-3]) # 80
# Slicing
print(arr[2:6]) # array('i', [30, 40, 50, 60])
print(arr[:4]) # array('i', [10, 20, 30, 40])
print(arr[6:]) # array('i', [70, 80, 90, 100])
print(arr[::2]) # array('i', [10, 30, 50, 70, 90])
print(arr[::-1]) # array('i', [100, 90, 80, 70, 60, 50, 40, 30, 20, 10])
# Multi-dimensional? No – arrays are 1D only
# For multi-dim, use NumPy
🛠️ 14.2 Array Operations – Complete Reference
➕ Inserting Elements
from array import array
arr = array('i', [10, 20, 30, 40, 50])
print(f"Original: {arr}")
# Append at end
arr.append(60)
print(f"After append(60): {arr}") # [10,20,30,40,50,60]
# Insert at specific position
arr.insert(2, 99)
print(f"After insert(2, 99): {arr}") # [10,20,99,30,40,50,60]
# Extend with multiple elements
arr.extend([70, 80, 90])
print(f"After extend([70,80,90]): {arr}") # ...70,80,90
# Insert at beginning
arr.insert(0, 5)
print(f"After insert(0,5): {arr}") # [5,10,20,99,...]
🔄 Updating Elements
# Update by index
arr[3] = 100
print(f"After arr[3] = 100: {arr}")
# Update slice (must match length!)
arr[1:4] = array('i', [11, 22, 33])
print(f"After slice update: {arr}")
# Cannot update with different type
# arr[0] = 3.14 # ❌ TypeError!
❌ Deleting Elements
from array import array
arr = array('i', [10, 20, 30, 40, 50, 60, 70])
# Remove by value (first occurrence)
arr.remove(40)
print(f"After remove(40): {arr}") # [10,20,30,50,60,70]
# Pop by index (returns removed value)
popped = arr.pop(2)
print(f"Popped value: {popped}") # 30
print(f"After pop(2): {arr}") # [10,20,50,60,70]
# Pop last item
last = arr.pop()
print(f"Last popped: {last}") # 70
print(f"After pop(): {arr}") # [10,20,50,60]
# Delete by index
del arr[1]
print(f"After del arr[1]: {arr}") # [10,50,60]
# Delete slice
del arr[1:3]
print(f"After del arr[1:3]: {arr}") # [10]
# Clear all
arr = array('i') # Reassign to empty
# or
arr[:] = array('i') # Slice assignment
🔄 Other Useful Operations
from array import array
arr = array('i', [5, 2, 8, 1, 9, 3, 7, 4, 6])
# Length
print(f"Length: {len(arr)}") # 9
# Check if element exists
print(8 in arr) # True
print(10 in arr) # False
# Count occurrences
print(arr.count(5)) # 1
# Find index
print(arr.index(7)) # 6
# Reverse in-place
arr.reverse()
print(f"After reverse: {arr}")
# Convert to list
as_list = arr.tolist()
print(f"As list: {as_list}")
# Convert to bytes
bytes_data = arr.tobytes()
print(f"Bytes length: {len(bytes_data)}")
# Sum (for numeric arrays)
print(f"Sum: {sum(arr)}")
# Min/Max
print(f"Min: {min(arr)}, Max: {max(arr)}")
# Sort (need to convert to list first)
sorted_arr = array('i', sorted(arr))
print(f"Sorted: {sorted_arr}")
📋 14.3 Complete Array Methods Reference
| Method | Description | Example | Result |
|---|---|---|---|
append(x) | Add item to end | arr.append(5) | Adds 5 |
buffer_info() | Get memory address & size | arr.buffer_info() | (address, length) |
byteswap() | Swap byte order | arr.byteswap() | Changes byte order |
count(x) | Count occurrences | arr.count(3) | Number of 3's |
extend(iterable) | Add multiple items | arr.extend([5,6,7]) | Adds 5,6,7 |
frombytes(b) | Append from bytes | arr.frombytes(data) | Adds bytes data |
fromfile(f, n) | Read n items from file | arr.fromfile(f, 5) | Reads 5 items |
fromlist(list) | Append from list | arr.fromlist([1,2,3]) | Adds list items |
fromunicode(s) | Append Unicode string | arr.fromunicode("hi") | Adds 'h','i' |
index(x) | Find first index | arr.index(30) | Index of 30 |
insert(i, x) | Insert at position | arr.insert(2, 99) | Inserts 99 at index 2 |
pop(i) | Remove and return item | arr.pop(3) | Removes item at index 3 |
remove(x) | Remove first occurrence | arr.remove(20) | Removes first 20 |
reverse() | Reverse in-place | arr.reverse() | Reverses array |
tobytes() | Convert to bytes | arr.tobytes() | Bytes object |
tofile(f) | Write to file | arr.tofile(f) | Writes to binary file |
tolist() | Convert to list | arr.tolist() | Python list |
tounicode() | Convert to Unicode string | arr.tounicode() | String (for 'u' type) |
📝 Detailed Examples
🔧 buffer_info() – Memory Information
from array import array
arr = array('i', [1, 2, 3, 4, 5])
info = arr.buffer_info()
print(f"Memory address: {info[0]}")
print(f"Number of items: {info[1]}")
print(f"Total bytes: {info[1] * arr.itemsize}")
# Useful for low-level operations
🔄 byteswap() – Endianness
arr = array('i', [1, 256, 65536])
print(f"Original: {arr}")
arr.byteswap() # Swap byte order
print(f"After byteswap: {arr}")
# Useful when reading binary data from different platforms
💾 File Operations
from array import array
import tempfile
import os
# Create temporary file
with tempfile.NamedTemporaryFile(delete=False) as tmp:
filename = tmp.name
# Write array to file
arr = array('i', [100, 200, 300, 400, 500])
with open(filename, 'wb') as f:
arr.tofile(f)
# Read array from file
new_arr = array('i')
with open(filename, 'rb') as f:
new_arr.fromfile(f, 3) # Read first 3 items
print(new_arr) # array('i', [100, 200, 300])
# Clean up
os.unlink(filename)
📦 Bytes Conversion
arr = array('i', [1, 2, 3, 4, 5])
# To bytes
bytes_data = arr.tobytes()
print(f"Bytes: {bytes_data}")
print(f"Bytes length: {len(bytes_data)}") # 5 * 4 = 20 bytes
# From bytes
new_arr = array('i')
new_arr.frombytes(bytes_data)
print(f"Recovered: {new_arr}")
📋 Type Conversion
arr = array('i', [1, 2, 3, 4, 5])
# To list
list_data = arr.tolist()
print(f"List: {list_data}")
print(f"Type: {type(list_data)}")
# To string (for 'u' type only)
char_arr = array('u', 'hello')
string = char_arr.tounicode()
print(f"String: {string}") # hello
⚖️ 14.4 Array vs List – Complete Comparison
| Feature | List | Array |
|---|---|---|
| Data Types | Heterogeneous (any types) | Homogeneous (single type) |
| Memory Usage | High (stores Python objects) | Low (stores C primitives) |
| Speed (access) | Moderate | Fast |
| Speed (operations) | Good | Better for numeric ops |
| Methods | Many (40+) | Fewer (15+) |
| Built-in | Yes (core Python) | Requires import |
| Multi-dimensional | Yes (nested lists) | No (1D only) |
| Type Safety | No (can mix types) | Yes (enforced) |
| Mathematical Ops | Limited | Basic only |
| Use Case | General purpose | Numeric data, memory critical |
📊 Performance Benchmarks
⚡ Memory Comparison
import sys
from array import array
# Create data
data = list(range(1000))
arr = array('i', range(1000))
# Compare sizes
list_size = sys.getsizeof(data) + sum(sys.getsizeof(x) for x in data)
arr_size = sys.getsizeof(arr)
print(f"List total size: ~{list_size:,} bytes")
print(f"Array size: {arr_size:,} bytes")
print(f"Array uses {list_size/arr_size:.1f}x less memory!")
# Output:
# List total size: ~28,000 bytes
# Array size: 4,000 bytes
# Array uses 7.0x less memory!
⚡ Speed Comparison
import time
from array import array
# Create large datasets
size = 10_000_000
list_data = list(range(size))
arr_data = array('i', range(size))
# Access speed test
start = time.time()
for i in range(0, size, 10000): # Sample every 10k
x = list_data[i]
list_time = time.time() - start
start = time.time()
for i in range(0, size, 10000):
x = arr_data[i]
arr_time = time.time() - start
print(f"List access time: {list_time:.4f}s")
print(f"Array access time: {arr_time:.4f}s")
print(f"Array is {list_time/arr_time:.2f}x faster")
📋 Decision Guide
# USE LIST WHEN:
# - You need to store mixed data types
# - You need multi-dimensional structures
# - You're doing general-purpose programming
# - You need many list-specific methods
# - Data size is small
# USE ARRAY WHEN:
# - All data is same type (especially numbers)
# - Memory usage is critical
# - You need better performance
# - You're working with binary files
# - You need type safety
# - Processing large numeric datasets
# EXAMPLE CHOICES:
# Student records (name, age, grade) → List
# Temperature readings from sensors → Array
# Shopping cart items → List
# Image pixel data → Array
# Mixed data from CSV → List
# Pure numeric calculations → Array
💼 14.5 When to Use Arrays – Real-World Applications
🌡️ 1. Sensor Data Logging
from array import array
import random
import time
class SensorLogger:
def __init__(self, sensor_name):
self.sensor_name = sensor_name
self.temperatures = array('f') # Float array
self.timestamps = array('i') # Integer array
def read_sensor(self):
# Simulate sensor reading
return 20.0 + random.random() * 10
def log_reading(self):
temp = self.read_sensor()
self.temperatures.append(temp)
self.timestamps.append(int(time.time()))
print(f"Logged: {temp:.2f}°C")
def statistics(self):
if len(self.temperatures) == 0:
return "No data"
temps = self.temperatures
return {
'min': min(temps),
'max': max(temps),
'avg': sum(temps) / len(temps),
'count': len(temps)
}
# Usage
logger = SensorLogger("Room Temp")
for _ in range(10):
logger.log_reading()
time.sleep(0.1)
print(logger.statistics())
📊 2. Statistical Analysis
from array import array
import math
class Statistics:
def __init__(self, data):
self.data = array('d', data) # Double precision
def mean(self):
return sum(self.data) / len(self.data)
def variance(self):
mean_val = self.mean()
return sum((x - mean_val) ** 2 for x in self.data) / len(self.data)
def std_dev(self):
return math.sqrt(self.variance())
def percentile(self, p):
sorted_data = sorted(self.data)
k = (len(sorted_data) - 1) * (p / 100)
f = math.floor(k)
c = math.ceil(k)
if f == c:
return sorted_data[int(k)]
return sorted_data[f] * (c-k) + sorted_data[c] * (k-f)
# Example usage
data = [random.gauss(100, 15) for _ in range(1000)]
stats = Statistics(data)
print(f"Mean: {stats.mean():.2f}")
print(f"Std Dev: {stats.std_dev():.2f}")
print(f"95th percentile: {stats.percentile(95):.2f}")
🖼️ 3. Image Processing (Grayscale)
from array import array
class GrayscaleImage:
def __init__(self, width, height):
self.width = width
self.height = height
self.pixels = array('B', [0] * (width * height)) # Unsigned char (0-255)
def set_pixel(self, x, y, value):
if 0 <= value <= 255:
self.pixels[y * self.width + x] = value
def get_pixel(self, x, y):
return self.pixels[y * self.width + x]
def apply_brightness(self, factor):
for i in range(len(self.pixels)):
self.pixels[i] = min(255, max(0, int(self.pixels[i] * factor)))
def invert(self):
for i in range(len(self.pixels)):
self.pixels[i] = 255 - self.pixels[i]]
def histogram(self):
hist = [0] * 256
for pixel in self.pixels:
hist[pixel] += 1
return hist
# Create 100x100 image
img = GrayscaleImage(100, 100)
img.set_pixel(10, 10, 200)
img.apply_brightness(1.2)
img.invert()
🎵 4. Audio Processing
from array import array
import math
class AudioBuffer:
def __init__(self, sample_rate=44100):
self.sample_rate = sample_rate
self.samples = array('h') # Signed short for audio
def generate_sine(self, frequency, duration):
"""Generate sine wave"""
num_samples = int(self.sample_rate * duration)
for i in range(num_samples):
t = i / self.sample_rate
value = int(32767 * math.sin(2 * math.pi * frequency * t))
self.samples.append(value)
def generate_square(self, frequency, duration):
"""Generate square wave"""
num_samples = int(self.sample_rate * duration)
period = self.sample_rate / frequency
for i in range(num_samples):
if (i % period) < period / 2:
self.samples.append(32767)
else:
self.samples.append(-32768)
def normalize(self):
"""Normalize audio to prevent clipping"""
max_val = max(abs(min(self.samples)), abs(max(self.samples)))
if max_val > 32767:
factor = 32767 / max_val
for i in range(len(self.samples)):
self.samples[i] = int(self.samples[i] * factor)
def mix(self, other):
"""Mix two audio buffers"""
min_len = min(len(self.samples), len(other.samples))
for i in range(min_len):
mixed = self.samples[i] + other.samples[i]
self.samples[i] = max(-32768, min(32767, mixed))
# Create audio
audio = AudioBuffer()
audio.generate_sine(440, 2.0) # 440 Hz for 2 seconds
audio.normalize()
📈 5. Financial Data Processing
from array import array
from datetime import datetime, timedelta
class StockData:
def __init__(self, symbol):
self.symbol = symbol
self.prices = array('d')
self.volumes = array('i')
self.dates = []
def add_day(self, date, price, volume):
self.dates.append(date)
self.prices.append(price)
self.volumes.append(volume)
def moving_average(self, window):
"""Calculate simple moving average"""
if len(self.prices) < window:
return []
ma = array('d')
for i in range(len(self.prices) - window + 1):
avg = sum(self.prices[i:i+window]) / window
ma.append(avg)
return ma
def volatility(self, window=20):
"""Calculate rolling volatility"""
if len(self.prices) < window:
return 0
returns = array('d')
for i in range(1, len(self.prices)):
returns.append((self.prices[i] - self.prices[i-1]) / self.prices[i-1])
# Calculate standard deviation of returns
mean_return = sum(returns[-window:]) / window
variance = sum((r - mean_return)**2 for r in returns[-window:]) / window
return math.sqrt(variance) * math.sqrt(252) # Annualized
# Example usage
stock = StockData("AAPL")
start_date = datetime(2024, 1, 1)
for i in range(100):
date = start_date + timedelta(days=i)
price = 150 + random.random() * 10
volume = random.randint(1000000, 5000000)
stock.add_day(date, price, volume)
ma_20 = stock.moving_average(20)
vol = stock.volatility()
print(f"20-day MA: {ma_20[-1]:.2f}")
print(f"Annualized volatility: {vol:.2%}")
🧮 6. Scientific Computing
from array import array
import math
class Vector3D:
def __init__(self, x, y, z):
self.components = array('d', [x, y, z])
def __add__(self, other):
return Vector3D(
self.components[0] + other.components[0],
self.components[1] + other.components[1],
self.components[2] + other.components[2]
)
def dot(self, other):
return sum(self.components[i] * other.components[i] for i in range(3))
def cross(self, other):
return Vector3D(
self.components[1] * other.components[2] - self.components[2] * other.components[1],
self.components[2] * other.components[0] - self.components[0] * other.components[2],
self.components[0] * other.components[1] - self.components[1] * other.components[0]
)
def magnitude(self):
return math.sqrt(sum(x**2 for x in self.components))
def normalize(self):
mag = self.magnitude()
if mag > 0:
return Vector3D(
self.components[0] / mag,
self.components[1] / mag,
self.components[2] / mag
)
return self
# Physics simulation
v1 = Vector3D(1, 2, 3)
v2 = Vector3D(4, 5, 6)
v3 = v1.cross(v2)
print(f"Cross product: ({v3.components[0]:.2f}, {v3.components[1]:.2f}, {v3.components[2]:.2f})")
📁 7. Binary File I/O
from array import array
import struct
class BinaryFileHandler:
@staticmethod
def write_integers(filename, data):
arr = array('i', data)
with open(filename, 'wb') as f:
arr.tofile(f)
@staticmethod
def read_integers(filename, count=None):
arr = array('i')
with open(filename, 'rb') as f:
if count:
arr.fromfile(f, count)
else:
arr.frombytes(f.read())
return arr
@staticmethod
def write_mixed_types(filename, data):
"""Write structured binary data"""
with open(filename, 'wb') as f:
for item in data:
# Pack: int (4 bytes), float (4 bytes), short (2 bytes)
packed = struct.pack('ifh', item['id'], item['value'], item['flag'])
f.write(packed)
@staticmethod
def read_mixed_types(filename):
result = []
record_size = struct.calcsize('ifh')
with open(filename, 'rb') as f:
while True:
data = f.read(record_size)
if not data:
break
id_val, value, flag = struct.unpack('ifh', data)
result.append({'id': id_val, 'value': value, 'flag': flag})
return result
# Usage
handler = BinaryFileHandler()
handler.write_integers('data.bin', [1,2,3,4,5])
data = handler.read_integers('data.bin')
print(data) # array('i', [1,2,3,4,5])
🎮 8. Game Development (Particles)
from array import array
import random
class ParticleSystem:
def __init__(self, max_particles):
self.max_particles = max_particles
# Use arrays for better performance
self.x = array('f', [0.0] * max_particles)
self.y = array('f', [0.0] * max_particles)
self.vx = array('f', [0.0] * max_particles)
self.vy = array('f', [0.0] * max_particles)
self.life = array('f', [0.0] * max_particles)
self.active_count = 0
def emit(self, count, x, y):
"""Emit new particles"""
for i in range(min(count, self.max_particles - self.active_count)):
idx = self.active_count
self.x[idx] = x
self.y[idx] = y
angle = random.uniform(0, 2 * 3.14159)
speed = random.uniform(50, 200)
self.vx[idx] = math.cos(angle) * speed
self.vy[idx] = math.sin(angle) * speed
self.life[idx] = 1.0 # Full life
self.active_count += 1
def update(self, dt):
"""Update all particles"""
for i in range(self.active_count):
# Update position
self.x[i] += self.vx[i] * dt
self.y[i] += self.vy[i] * dt
# Apply gravity
self.vy[i] -= 9.8 * dt
# Reduce life
self.life[i] -= dt
# Remove dead particles
if self.life[i] <= 0:
self.active_count -= 1
# Swap with last active particle
self.x[i] = self.x[self.active_count]
self.y[i] = self.y[self.active_count]
self.vx[i] = self.vx[self.active_count]
self.vy[i] = self.vy[self.active_count]
self.life[i] = self.life[self.active_count]
i -= 1
# Usage
particles = ParticleSystem(1000)
particles.emit(100, 400, 300)
for _ in range(100):
particles.update(0.016) # 60 FPS
🔬 9. Scientific Data Acquisition
from array import array
import time
import threading
class DataAcquisition:
def __init__(self, channels=8, sample_rate=1000):
self.channels = channels
self.sample_rate = sample_rate
self.buffers = [array('h') for _ in range(channels)]
self.running = False
def start_acquisition(self):
self.running = True
self.thread = threading.Thread(target=self._acquire_data)
self.thread.start()
def stop_acquisition(self):
self.running = False
self.thread.join()
def _acquire_data(self):
while self.running:
# Simulate ADC reading
for ch in range(self.channels):
# Read 16-bit signed value from hardware
value = int((random.random() * 2 - 1) * 32767)
self.buffers[ch].append(value)
# Maintain sample rate
time.sleep(1.0 / self.sample_rate)
def get_channel_data(self, channel):
return self.buffers[channel]
def clear_buffers(self):
for ch in range(self.channels):
self.buffers[ch] = array('h')
def calculate_fft(self, channel):
"""Simplified FFT placeholder"""
data = self.buffers[channel]
if len(data) < 2:
return []
# Real FFT would go here
return [abs(x) for x in data[:len(data)//2]]
# Usage
daq = DataAcquisition(channels=4, sample_rate=100)
daq.start_acquisition()
time.sleep(1) # Acquire for 1 second
daq.stop_acquisition()
ch1_data = daq.get_channel_data(0)
print(f"Acquired {len(ch1_data)} samples on channel 0")
📦 10. Memory Pool / Object Pool
from array import array
class IntPool:
"""Memory-efficient pool of integers"""
def __init__(self, initial_size=1000):
self.pool = array('i', [0] * initial_size)
self.used = array('b', [0] * initial_size) # Boolean flags
self.size = initial_size
def allocate(self, value):
"""Find free slot and store value"""
for i in range(self.size):
if not self.used[i]:
self.pool[i] = value
self.used[i] = 1
return i
# Pool full, expand
new_size = self.size * 2
self.pool.extend([0] * (new_size - self.size))
self.used.extend([0] * (new_size - self.size))
self.size = new_size
return self.allocate(value)
def deallocate(self, index):
"""Free slot"""
if 0 <= index < self.size:
self.used[index] = 0
def get(self, index):
"""Get value at index"""
if 0 <= index < self.size and self.used[index]:
return self.pool[index]
raise ValueError("Invalid index or not allocated")
def defrag(self):
"""Compact used slots (remove holes)"""
new_pool = array('i')
new_used = array('b')
for i in range(self.size):
if self.used[i]:
new_pool.append(self.pool[i])
new_used.append(1)
# Fill rest with zeros
remaining = self.size - len(new_pool)
new_pool.extend([0] * remaining)
new_used.extend([0] * remaining)
self.pool = new_pool
self.used = new_used
# Usage
pool = IntPool(10)
idx1 = pool.allocate(42)
idx2 = pool.allocate(99)
print(pool.get(idx1)) # 42
pool.deallocate(idx1)
pool.defrag()
✅ Array Module Good For:
- Memory-efficient storage of primitive types
- Simple numeric collections
- Binary file I/O
- When you can't install NumPy
- Learning fundamentals
⚠️ When NumPy is Better:
- Multi-dimensional arrays
- Linear algebra operations
- Fast element-wise operations
- Broadcasting
- Scientific computing
- Machine learning
# NumPy example (much more powerful)
import numpy as np
# Multi-dimensional array
matrix = np.array([[1, 2, 3], [4, 5, 6]])
# Element-wise operations
result = matrix * 2 # Multiply every element by 2
# Linear algebra
dot_product = np.dot(matrix, matrix.T)
# Broadcasting
a = np.array([1, 2, 3])
b = np.array([10, 20, 30])
result = a[:, np.newaxis] + b # Outer addition
# Array module can't do any of this!
What type code would you use for a float array (4 bytes)?
Can an array store different data types?
How do you create an integer array from a list [1,2,3]?
Which is more memory efficient for 1 million integers – list or array?
🏆 Challenge Problems
# Challenge 1: Implement moving average using array
def moving_average(data, window):
arr = array('d', data)
result = array('d')
for i in range(len(arr) - window + 1):
avg = sum(arr[i:i+window]) / window
result.append(avg)
return result
# Challenge 2: Read binary file of integers
def read_integers(filename):
arr = array('i')
with open(filename, 'rb') as f:
arr.fromfile(f, -1) # Read all
return arr
# Challenge 3: Convert between list and array efficiently
def list_to_array(lst, typecode='i'):
return array(typecode, lst)
def array_to_list(arr):
return arr.tolist()
# Challenge 4: Find duplicates in array
def find_duplicates(arr):
seen = set()
duplicates = set()
for x in arr:
if x in seen:
duplicates.add(x)
seen.add(x)
return array('i', duplicates)
# Challenge 5: Matrix multiplication using arrays (1D storage)
def matrix_multiply(A, B, rowsA, colsA, colsB):
"""A and B are 1D arrays stored row-major"""
result = array('i', [0] * (rowsA * colsB))
for i in range(rowsA):
for j in range(colsB):
total = 0
for k in range(colsA):
total += A[i * colsA + k] * B[k * colsB + j]
result[i * colsB + j] = total
return result
🎓 Module 14 : Python Array (Concept & Practical Use) Successfully Completed
You have successfully completed this module of Python for Cybersecurity.
Keep building your expertise step by step — Learn Next Module →
⏰ Python Date & Time – Working with datetime Module
Python’s datetime module allows you to work with dates, times, time differences, and formatting. It is extremely useful in logs, timers, scheduling, timestamps, and automation.
15.1 datetime Module Explained Easily
Import datetime like this:
import datetime
✔ Get Current Date & Time
import datetime
now = datetime.datetime.now()
print(now)
✔ Get Only Today's Date
today = datetime.date.today()
print(today)
✔ Get Only Current Time
time_now = datetime.datetime.now().time()
print(time_now)
15.2 Formatting Dates (strftime)
strftime() converts date/time into readable string formats.
| Format Code | Meaning | Example Output |
|---|---|---|
%d |
Day | 05 |
%m |
Month | 12 |
%Y |
Year (full) | 2025 |
%H |
Hour (24-hour) | 14 |
%M |
Minute | 45 |
✔ Example of Formatting
import datetime
now = datetime.datetime.now()
print(now.strftime("%d-%m-%Y")) # 05-12-2025
print(now.strftime("%H:%M:%S")) # 14:45:22
print(now.strftime("%A")) # Monday
15.3 Time Calculations
You can extract individual parts of the date/time.
now = datetime.datetime.now()
print(now.day) # 5
print(now.month) # 12
print(now.year) # 2025
print(now.hour) # 14
print(now.minute) # 47
✔ Add Time
future = now + datetime.timedelta(days=10)
print(future)
✔ Subtract Time
past = now - datetime.timedelta(hours=5)
print(past)
15.4 timedelta – Working with Date Differences
timedelta is used to calculate the difference between two dates.
date1 = datetime.date(2025, 5, 1)
date2 = datetime.date(2025, 5, 20)
difference = date2 - date1
print(difference.days) # 19
15.5 Real Use Cases (Timers, Logs, Scheduling)
✔ Example 1: Timestamp for Logs
log_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
print("Log entry at:", log_time)
✔ Example 2: Countdown Timer
event = datetime.datetime(2025, 12, 31)
today = datetime.datetime.now()
remaining = event - today
print("Days remaining:", remaining.days)
✔ Example 3: Auto-Generated Date in Reports
report_date = datetime.date.today()
print("Report generated on:", report_date)
🎓 Module 15 : Python Date & Time (Working with datetime) Successfully Completed
You have successfully completed this module of Python for Cybersecurity.
Keep building your expertise step by step — Learn Next Module →
📂 Python File Handling – Read & Write Files
Python makes it easy to work with files — reading data, writing content, updating files, and managing directories. File handling is essential for logs, reports, storage, and automation.
16.1 Reading Files (open, read, readline)
To work with files, Python uses the open() function.
| Mode | Description |
|---|---|
"r" |
Read (default) |
"w" |
Write (overwrites file) |
"a" |
Append (adds at end) |
"x" |
Create new file (fails if exists) |
✔ Read Entire File
f = open("demo.txt", "r")
print(f.read())
f.close()
✔ Read First Line
f = open("demo.txt", "r")
print(f.readline())
f.close()
16.2 Writing Files Safely
"w" will overwrite entire file, so use carefully!
✔ Writing Text into File
f = open("notes.txt", "w")
f.write("Hello, this is new content!")
f.close()
✔ Append (Add without removing old data)
f = open("notes.txt", "a")
f.write("\nThis line is added later.")
f.close()
16.3 File Modes Explained Simply
| Mode | Description | Example |
|---|---|---|
r |
Read only | open("a.txt","r") |
w |
Write (overwrite) | open("a.txt","w") |
a |
Append | open("a.txt","a") |
r+ |
Read & Write | open("a.txt","r+") |
b |
Binary files (images, videos) | open("img.jpg","rb") |
16.4 Working with Directories (os module)
Python’s os module helps manage folders, filenames, and file paths.
import os
print(os.getcwd()) # Current directory
os.mkdir("myfolder") # Create folder
os.listdir() # List files/folders
os.rename("old.txt", "new.txt") # Rename file
16.5 Exception Handling in File Input/Output
Always handle missing files safely.
✔ Example with Try–Except
try:
f = open("unknown.txt", "r")
print(f.read())
except FileNotFoundError:
print("File does not exist!")
✔ Best Practice: Use "with" (auto-closes file)
with open("data.txt", "r") as f:
print(f.read())
🎓 Module 16 : File Handling (Read & Write Files) Successfully Completed
You have successfully completed this module of Python for Cybersecurity.
Keep building your expertise step by step — Learn Next Module →
🧵 Multithreading – Run Tasks in Parallel
Multithreading allows Python to run multiple tasks at the same time — useful for downloading files, sending emails, handling network tasks, or processing data. Although Python has the GIL, multithreading is still powerful for I/O-based tasks.
17.1 What is Multithreading?
Multithreading means running multiple operations concurrently within a program.
✔ Why Use Multithreading?
- 🚀 Improves performance for I/O tasks
- 📥 Helps download multiple files at once
- 📩 Useful for sending many emails in background
- 🔄 Keeps applications responsive
✔ Importing the Thread Module
from threading import Thread
17.2 How to Create Threads
There are two common ways to create threads:
➡️ Method 1: Create a Thread Using a Function
from threading import Thread
import time
def task():
print("Task is running...")
time.sleep(2)
t = Thread(target=task)
t.start()
print("Main program continues...")
➡️ Method 2: Create a Thread Using a Class
from threading import Thread
class MyThread(Thread):
def run(self):
print("Thread running using class method")
t = MyThread()
t.start()
17.3 Race Conditions Explained Simply
A race condition happens when two threads try to access or modify the same data at the same time.
✔ Problem Example
counter = 0
def increment():
global counter
for i in range(100000):
counter += 1
Multiple threads running this at once will produce incorrect results.
17.4 Locks & Synchronization
Locks prevent multiple threads from accessing the same resource at the same time. They help avoid race conditions.
✔ Using Lock in Python
from threading import Thread, Lock
lock = Lock()
counter = 0
def safe_increment():
global counter
for i in range(100000):
with lock: # Only one thread allowed here
counter += 1
t1 = Thread(target=safe_increment)
t2 = Thread(target=safe_increment)
t1.start()
t2.start()
t1.join()
t2.join()
print(counter)
17.5 Multithreading Use Cases (Easy Examples)
Multithreading is useful in many real-life scenarios:
-
Downloading Multiple Files
Thread(target=download_file, args=("file1.jpg",)).start() Thread(target=download_file, args=("file2.jpg",)).start() -
Sending Multiple Emails
for email in email_list: Thread(target=send_mail, args=(email,)).start() -
Real-Time Applications
- Video games 🎮
- Chat apps 💬
- Live data processing 📊
🎓 Module 17 : Multithreading (Run Tasks in Parallel) Successfully Completed
You have successfully completed this module of Python for Cybersecurity.
Keep building your expertise step by step — Learn Next Module →
📧 Python Mail Sending Program – SMTP Basics
This module introduces how to send emails using Python’s built-in SMTP (Simple Mail Transfer Protocol). You’ll learn how email works, how to send simple messages, attach files, send HTML emails, and automate email workflows.
18.1 What is SMTP – How Email Works?
SMTP is the protocol used to send emails across the internet. Python includes a built-in module called smtplib that allows you to send emails programmatically.
✔ How Email Sending Works
- ✉ You write an email in Python
- 🔐 Python connects to the SMTP server (Gmail, Yahoo, Outlook, etc.)
- 📤 The server sends your email to the recipient
Common SMTP Servers
| Email Provider | SMTP Server | Port |
|---|---|---|
| Gmail | smtp.gmail.com | 587 |
| Yahoo | smtp.mail.yahoo.com | 587 |
| Outlook | smtp.office365.com | 587 |
18.2 Sending Simple Emails
You can send a basic email using only a few lines of code using
smtplib and email.mime modules.
import smtplib
from email.mime.text import MIMEText
sender = "yourmail@gmail.com"
password = "your-app-password"
receiver = "receiver@example.com"
message = MIMEText("Hello, this is a test email sent using Python!")
message["Subject"] = "Test Email"
message["From"] = sender
message["To"] = receiver
server = smtplib.SMTP("smtp.gmail.com", 587)
server.starttls()
server.login(sender, password)
server.send_message(message)
server.quit()
print("Email sent successfully!")
18.3 Sending Attachments (Easy Explanation)
You can attach images, PDFs, Word files, etc., using MIMEBase.
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email.mime.text import MIMEText
from email import encoders
sender = "yourmail@gmail.com"
receiver = "receiver@example.com"
password = "your-app-password"
msg = MIMEMultipart()
msg["Subject"] = "Email with Attachment"
msg["From"] = sender
msg["To"] = receiver
# Email body
msg.attach(MIMEText("Please find the attached file.", "plain"))
# Attachment
file = "report.pdf"
attachment = open(file, "rb")
mime = MIMEBase("application", "octet-stream")
mime.set_payload(attachment.read())
attachment.close()
encoders.encode_base64(mime)
mime.add_header("Content-Disposition", f"attachment; filename={file}")
msg.attach(mime)
server = smtplib.SMTP("smtp.gmail.com", 587)
server.starttls()
server.login(sender, password)
server.sendmail(sender, receiver, msg.as_string())
server.quit()
print("Email with attachment sent!")
18.4 Sending HTML Emails
HTML emails allow you to include colors, buttons, images, and styled content.
import smtplib from email.mime.text import MIMEText html = """Welcome!
This is an HTML Email sent using Python.
""" message = MIMEText(html, "html") message["Subject"] = "HTML Email Example" message["From"] = "yourmail@gmail.com" message["To"] = "receiver@example.com" server = smtplib.SMTP("smtp.gmail.com", 587) server.starttls() server.login("yourmail@gmail.com", "your-app-password") server.send_message(message) server.quit() print("HTML email sent!")
18.5 Automating Emails with Python
Python can send emails automatically — useful for reminders, notifications, marketing, or system alerts.
✔ Example: Send Email Every Morning
import schedule
import time
import smtplib
from email.mime.text import MIMEText
def send_daily_reminder():
msg = MIMEText("This is your daily reminder!")
msg["Subject"] = "Daily Reminder"
msg["From"] = "yourmail@gmail.com"
msg["To"] = "receiver@example.com"
server = smtplib.SMTP("smtp.gmail.com", 587)
server.starttls()
server.login("yourmail@gmail.com", "your-app-password")
server.send_message(msg)
server.quit()
schedule.every().day.at("09:00").do(send_daily_reminder)
while True:
schedule.run_pending()
time.sleep(1)
🎓 Module 18 : Python Mail Sending Program (SMTP Basics) Successfully Completed
You have successfully completed this module of Python for Cybersecurity.
Keep building your expertise step by step — Learn Next Module →
🗄️ Database Connection – MySQL & SQLite
This module teaches how Python communicates with databases such as MySQL and SQLite. You will learn how to connect, insert data, fetch data, update and delete records, handle errors, and follow best practices.
19.1 How to Connect to MySQL
To connect Python to MySQL, we use the package
mysql-connector-python.
pip install mysql-connector-python
✔ Connecting Python to MySQL
import mysql.connector
connection = mysql.connector.connect(
host="localhost",
user="root",
password="yourpassword",
database="testdb"
)
print("MySQL Connected Successfully!")
connection.close()
MySQL Connection Parameters
| Parameter | Description |
|---|---|
| host | Database server location |
| user | Your MySQL username |
| password | Your MySQL password |
| database | Name of the database |
19.2 CRUD Operations (Create, Read, Update, Delete)
CRUD operations are the foundation of all database work. Let's learn them step-by-step with clear examples.
🟢 CREATE – Insert Data
cursor = connection.cursor()
query = "INSERT INTO students (name, age) VALUES (%s, %s)"
data = ("John", 21)
cursor.execute(query, data)
connection.commit()
print("Data inserted successfully!")
🔵 READ – Fetch Data
cursor.execute("SELECT * FROM students")
rows = cursor.fetchall()
for row in rows:
print(row)
🟡 UPDATE – Modify Data
query = "UPDATE students SET age = %s WHERE name = %s"
cursor.execute(query, (22, "John"))
connection.commit()
print("Record updated!")
🔴 DELETE – Remove Data
query = "DELETE FROM students WHERE name = %s"
cursor.execute(query, ("John",))
connection.commit()
print("Record deleted!")
19.3 Handling Database Errors
Errors can happen—wrong credentials, wrong query, server not running, etc.
Python provides clean error handling using try-except.
import mysql.connector
from mysql.connector import Error
try:
connection = mysql.connector.connect(
host="localhost",
user="root",
password="wrongpass",
database="testdb"
)
except Error as e:
print("Error:", e)
Common MySQL Errors
- ❌ Wrong username/password
- ❌ Database does not exist
- ❌ MySQL server not running
- ❌ Incorrect SQL query syntax
19.4 Introduction to SQLite
SQLite is a lightweight, file-based database used in mobile apps, small projects, and local storage. It requires no installation.
✔ Connect to SQLite
import sqlite3
connection = sqlite3.connect("mydatabase.db")
cursor = connection.cursor()
print("SQLite connected!")
CRUD Example in SQLite
cursor.execute("CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT)")
cursor.execute("INSERT INTO users (name) VALUES ('Alice')")
connection.commit()
cursor.execute("SELECT * FROM users")
print(cursor.fetchall())
19.5 Database Best Practices
To build professional applications, follow these recommended practices:
- 🔐 Always use secure credentials
- 📁 Close connections after use
- ⚡ Use prepared statements to avoid SQL injection
- 📝 Validate all input before using in queries
- 🚀 Use connection pooling for large applications
🎓 Module 19 : Database Connection (MySQL & SQLite) Successfully Completed
You have successfully completed this module of Python for Cybersecurity.
Keep building your expertise step by step — Learn Next Module →
🧩 Object-Oriented Programming (OOP) in Python
OOP (Object-Oriented Programming) is a method of structuring programs by bundling data & functions into reusable components called objects. Python is a fully OOP-supported language, making software development clean, scalable, and organized.
20.1 What are Classes & Objects?
OOP revolves around two main ideas: Class and Object.
✔ Class (Blueprint)
A class is a template or blueprint that defines how an object should be created.
✔ Object (Instance)
An object is a real instance of a class that contains data (variables) and behaviour (functions).
✔ Python Example
class Car:
brand = "Toyota"
color = "Red"
# Creating object
my_car = Car()
print(my_car.brand)
print(my_car.color)
20.2 Inheritance – Reuse Code Easily
Inheritance allows one class to use the properties and methods of another class. It increases reusability and reduces code repetition.
✔ Parent Class → Child Class
class Animal:
def sound(self):
print("This animal makes a sound")
class Dog(Animal):
def bark(self):
print("Dog barks!")
pet = Dog()
pet.sound()
pet.bark()
sound() and bark().
Types of Inheritance
| Type | Description |
|---|---|
| Single | One parent → one child |
| Multiple | Child inherits from multiple parents |
| Multilevel | Parent → Child → Grandchild |
| Hierarchical | Multiple children from one parent |
| Hybrid | Combination of multiple inheritance types |
20.3 Polymorphism – One Function, Many Forms
Polymorphism allows the same function name to behave differently for different objects.
✔ Example in Python
class Bird:
def make_sound(self):
print("Bird chirps")
class Dog:
def make_sound(self):
print("Dog barks")
def play_sound(animal):
animal.make_sound()
play_sound(Bird())
play_sound(Dog())
make_sound() behaves differently for each object → this is polymorphism.
Real-Life Example
- 📱 Pressing a button → Camera opens on phone
- 💻 Pressing same button → Takes screenshot on laptop
20.4 Encapsulation – Hide Internal Details
Encapsulation means protecting data by restricting access through methods only.
✔ Private Variables
class BankAccount:
def __init__(self):
self.__balance = 1000 # Private variable
def deposit(self, amount):
self.__balance += amount
def show_balance(self):
print("Balance:", self.__balance)
account = BankAccount()
account.deposit(500)
account.show_balance()
account.__balance ❌
20.5 Abstraction – Only Show What’s Needed
Abstraction hides complex details and exposes only necessary functions.
✔ Example
from abc import ABC, abstractmethod
class Vehicle(ABC):
@abstractmethod
def start(self):
pass
class Car(Vehicle):
def start(self):
print("Car engine started")
car = Car()
car.start()
🎓 Module 20 : OOPs Concepts (Object-Oriented Programming) Successfully Completed
You have successfully completed this module of Python for Cybersecurity.
Keep building your expertise step by step — Learn Next Module →
🌐 Interacting with Networks in Python
This module explains how Python interacts with computer networks using sockets, HTTP requests, and APIs. You will learn the basics of sending/receiving data, creating simple clients & servers, and safely accessing online resources.
21.1 Understanding Sockets (Very Simple)
A socket is the connection point between two computers. It allows them to send and receive data just like phone lines.
✔ Types of Sockets
| Socket Type | Description |
|---|---|
| TCP Socket | Reliable, connection-based |
| UDP Socket | Fast, connectionless |
✔ Simple TCP Client (Connect to Server)
import socket
client = socket.socket()
client.connect(("127.0.0.1", 9000))
client.send("Hello Server".encode())
data = client.recv(1024)
print("Received:", data.decode())
client.close()
✔ Simple TCP Server
import socket
server = socket.socket()
server.bind(("127.0.0.1", 9000))
server.listen(1)
print("Server running...")
conn, addr = server.accept()
print("Connected:", addr)
data = conn.recv(1024).decode()
print("Client says:", data)
conn.send("Welcome Client!".encode())
conn.close()
21.2 HTTP Requests (Concept Only)
HTTP is the protocol used by websites. Python can send GET and POST requests to interact with web servers.
✔ GET Request Example
import requests
response = requests.get("https://api.github.com")
print("Status:", response.status_code)
print("Data:", response.json())
✔ POST Request Example
import requests
data = {"name": "John", "age": 25}
response = requests.post("https://example.com/api", json=data)
print("Server Response:", response.text)
21.3 APIs – How Python Talks to Websites
API stands for Application Programming Interface. It allows apps to talk to each other — like your phone app fetching weather or sending messages.
✔ Fetch Weather via API (Example)
import requests
api = "https://api.weatherapi.com/v1/current.json"
params = {
"key": "your_api_key",
"q": "London"
}
response = requests.get(api, params=params)
data = response.json()
print("Temperature:", data["current"]["temp_c"])
Real-Life API Uses
- 📱 Login with Google
- 📦 Track courier packages
- 💳 Online payments (Razorpay, Stripe)
- 📸 Upload photos to Instagram
21.4 Basic Networking Tools in Python
Python provides many built-in modules for networking tasks.
| Module | Purpose |
|---|---|
| socket | Low-level network communication |
| requests | HTTP requests (GET, POST) |
| urllib | URL handling |
| ftplib | FTP file transfer |
| smtplib | Email sending (SMTP) |
✔ Example: Check if Website is Online
import requests
try:
requests.get("https://google.com")
print("Website is Online!")
except:
print("Website is Offline!")
21.5 Safe & Ethical Network Use
Networking tools are powerful — but must always be used responsibly.
- ✔ Access only authorized systems
- ✔ Never perform scanning without permission
- ✔ Don’t overload servers with too many requests
- ✔ Always use HTTPS for secure communication
🎓 Module 21 : Interacting with Networks (Basic Networking in Python) Successfully Completed
You have successfully completed this module of Python for Cybersecurity.
Keep building your expertise step by step — Learn Next Module →
🖥️ Graphical User Interface (GUI Programming with Tkinter)
This module introduces Tkinter, Python’s standard GUI (Graphical User Interface) library. You will learn how to create windows, buttons, input fields, and interactive GUI applications easily.
22.1 Introduction to Tkinter (Easy GUI)
Tkinter is Python’s built-in library for creating desktop applications such as calculators, forms, tools, dashboards, and more.
✔ How to Import Tkinter
import tkinter as tk
✔ Create Your First GUI Window
import tkinter as tk
window = tk.Tk()
window.title("My First GUI")
window.geometry("300x200")
window.mainloop()
22.2 Basic GUI Components
Tkinter provides many simple components called widgets to build GUI apps.
| Widget | Description |
|---|---|
| Label | Displays text |
| Entry | Text input box |
| Button | Clickable button |
| Text | Multi-line input |
| Frame | Container for grouping widgets |
✔ Example: Adding Widgets
import tkinter as tk
win = tk.Tk()
win.title("Widgets Example")
tk.Label(win, text="Enter Name:").pack()
tk.Entry(win).pack()
tk.Button(win, text="Submit").pack()
win.mainloop()
22.3 Handling Buttons & Events
Buttons become useful when they perform an action using a function.
✔ Example: Button Click Event
import tkinter as tk
def say_hello():
print("Hello User!")
win = tk.Tk()
win.title("Event Example")
tk.Button(win, text="Click Me", command=say_hello).pack()
win.mainloop()
22.4 Build a Simple GUI App
Let’s build a simple name greeting application.
import tkinter as tk
def greet():
name = entry.get()
label_result.config(text="Hello, " + name)
win = tk.Tk()
win.title("Greeting App")
win.geometry("300x200")
tk.Label(win, text="Your Name:").pack()
entry = tk.Entry(win)
entry.pack()
tk.Button(win, text="Greet Me", command=greet).pack()
label_result = tk.Label(win, text="")
label_result.pack()
win.mainloop()
22.5 GUI Best Practices
- ✔ Keep the interface simple and clean
- ✔ Use frames to group widgets
- ✔ Avoid too many colors or fonts
- ✔ Use meaningful button names (Save, Submit, Upload)
- ✔ Test the GUI on different screen sizes
🎓 Module 22 : Graphical User Interface (GUI Programming) Successfully Completed
You have successfully completed this module of Python for Cybersecurity.
Keep building your expertise step by step — Learn Next Module →
🌐 Python Web Scraping – BeautifulSoup Concepts
This module explains how Python collects information from websites using simple web scraping techniques. You will learn concepts, HTML structure, tags, scraping workflow, and ethical rules. (No illegal scraping!)
23.1 What is Web Scraping?
Web scraping means extracting useful information from websites automatically using a program.
✔ Common Uses of Web Scraping
- ✔ Price comparison websites
- ✔ Job listing aggregators
- ✔ Data collection for research
- ✔ Social media analytics
- ✔ Competitor monitoring
23.2 Understanding HTML Structure
Web scraping requires understanding how HTML pages are built. Websites are made up of tags such as:
| Tag | Purpose |
|---|---|
| <h1> | Headings |
| <p> | Paragraph |
| <div> | Container for content |
| <span> | Inline small content |
| <a> | Links |
<div class="product">
<h2>Apple iPhone 15</h2>
<span class="price">$799</span>
</div>
23.3 BeautifulSoup (Concept Only)
BeautifulSoup is a Python package that helps extract content from HTML pages easily.
✔ Step-by-Step Scraping Flow
- Send request to website using requests
- Receive HTML source code
- Parse HTML using BeautifulSoup
- Find required tags
- Extract text or attributes
✔ Simple Conceptual Example
from bs4 import BeautifulSoup
html = "<h1>Hello World</h1>"
soup = BeautifulSoup(html, "html.parser")
print(soup.h1.text) # Output: Hello World
23.4 Extracting Data Safely
Here is an example of scraping product titles from a sample web page.
import requests
from bs4 import BeautifulSoup
url = "https://example.com/products"
response = requests.get(url)
soup = BeautifulSoup(response.text, "html.parser")
products = soup.find_all("h2", class_="title")
for p in products:
print(p.text)
❗ Avoid Heavy Scraping
- ❌ Sending too many requests
- ❌ Using fake identities
- ❌ Scraping personal/private data
23.5 Legal & Ethical Guidelines
Web scraping is powerful, but it must follow rules and respect privacy.
- ✔ Always check website robots.txt
- ✔ Scrape only publicly available data
- ✔ Never overload a website with requests
- ✔ Do not scrape login-protected areas
- ✔ Cite or credit website sources when needed
🎓 Module 23 : Python Web Scraping (Concept Based) Successfully Completed
You have successfully completed this module of Python for Cybersecurity.
Keep building your expertise step by step — Learn Next Module →
🖼️ Python for Image Processing – Beginner Friendly
This module introduces you to Python image processing concepts using PIL/Pillow. You will learn how images work, how to load, display, transform, and save them with simple and beginner-friendly examples.
24.1 What is Image Processing?
Image processing is the technique of performing operations on images to enhance them, extract useful information, or modify them for specific use cases.
✔ Where Image Processing is Used
- ✔ Face detection in cameras
- ✔ Filters in Instagram/Snapchat
- ✔ Medical image analysis (X-ray, MRI)
- ✔ Number plate recognition
- ✔ Object detection in AI
24.2 Opening & Reading Images Conceptually
To work with images in Python, install Pillow first:
pip install pillow
✔ Load & Display an Image
from PIL import Image
img = Image.open("nature.jpg")
img.show()
Pillow supports formats like JPEG, PNG, BMP, GIF.
24.3 Basic Transformations (Resize, Crop, Rotate)
Image manipulation is extremely easy with Pillow. Here are the essential transformations:
✔ Resize Image
resized = img.resize((300, 300))
resized.show()
✔ Rotate Image
rotated = img.rotate(45)
rotated.show()
✔ Crop Part of Image
cropped = img.crop((50, 50, 200, 200)) # (left, top, right, bottom)
cropped.show()
24.4 Filters & Enhancements (Easy Guide)
Pillow has built-in filters that help you modify image brightness, sharpness, contrast, etc.
✔ Apply Built-In Filters
from PIL import ImageFilter
blurred = img.filter(ImageFilter.BLUR)
blurred.show()
edge_image = img.filter(ImageFilter.FIND_EDGES)
edge_image.show()
✔ Enhance Image Quality
from PIL import ImageEnhance
b = ImageEnhance.Brightness(img)
bright_img = b.enhance(1.5) # Increase brightness
bright_img.show()
c = ImageEnhance.Contrast(img)
high_contrast = c.enhance(2)
high_contrast.show()
24.5 Real Use Cases in Daily Life
Python image processing is used everywhere. Here are real examples:
- ✔ Auto-resizing images for websites
- ✔ Converting images from PNG → JPG
- ✔ Blur faces for privacy (YouTube vlogs)
- ✔ Creating thumbnails automatically
- ✔ Applying artistic filters
✔ Saving the Edited Image
edited = img.resize((400, 400))
edited.save("edited_image.jpg")
🎓 Module 24 : Python for Image Processing (Beginner Friendly) Successfully Completed
You have successfully completed this module of Python for Cybersecurity.
Keep building your expertise step by step — Learn Next Module →
📊 Python Data Science – Conceptual Learning
This module introduces the core concepts of Data Science using Python. You will learn what Data Science is, how data is cleaned, analyzed, visualized, and used in real-world applications. No coding depth — only beginner-friendly conceptual understanding.
25.1 What is Data Science?
Data Science is the field of turning raw data into meaningful insights using statistics, programming, and visualization techniques.
🎯 Why Data Science is Important
- ✔ Helps companies make data-driven decisions
- ✔ Predicts customer behavior
- ✔ Improves business processes
- ✔ Powers AI, ML, and automation
🧠 Data Science Workflow (Simple Explanation)
| Step | Description |
|---|---|
| 1. Data Collection | Gathering data from websites, databases, APIs, etc. |
| 2. Data Cleaning | Removing errors, duplicates, missing values. |
| 3. Data Analysis | Understanding patterns and trends. |
| 4. Data Visualization | Graphs and charts for easy understanding. |
| 5. Decision Making | Using results to guide business decisions. |
25.2 Data Cleaning Concepts
Data cleaning is the most important step in Data Science. 70–80% of a data scientist’s time is spent cleaning and preparing data.
✔ Common Data Problems
- ❌ Missing values
- ❌ Duplicate rows
- ❌ Incorrect data types
- ❌ Outliers (extreme values)
✔ How Data is Cleaned (Concept Only)
- ✔ Filling missing values (mean/median)
- ✔ Removing duplicates
- ✔ Standardizing formats (date, number, text)
- ✔ Handling outliers
25.3 Data Visualization Explanation
Data visualization helps convert numbers into visual stories. Python uses tools like Matplotlib, Seaborn, Plotly for charts.
✔ Why Visualization is Important
- ✔ Makes data easy to understand
- ✔ Shows patterns, trends & insights
- ✔ Helps in decision-making
📊 Common Types of Charts
| Chart Type | Used For |
|---|---|
| Bar Chart | Comparing categories |
| Line Chart | Trends over time |
| Pie Chart | Percentage distribution |
| Histogram | Distribution of data |
| Scatter Plot | Relationship between variables |
25.4 Basic Statistics for Beginners
Statistics is the backbone of Data Science. You don't need deep math — just the basics.
✔ Key Statistical Concepts (Simple)
- Mean – Average value
- Median – Middle value
- Mode – Most common value
- Range – Highest − lowest
- Standard Deviation – Spread of data
25.5 Real-Life Data Science Projects
Here are simple real-world applications of Data Science:
- ✔ Predicting house prices
- ✔ Recommending movies (Netflix algorithm)
- ✔ Analyzing customer purchase patterns
- ✔ Detecting spam emails
- ✔ Forecasting sales for businesses
💬 Example Scenario
🎓 Module 25 : Python Data Science (Conceptual Learning) Successfully Completed
You have successfully completed this module of Python for Cybersecurity.
Keep building your expertise step by step — Learn Next Module →
🤖 Python Machine Learning – Conceptual Introduction
This module introduces the fundamentals of Machine Learning using Python. No complicated mathematics — only easy-to-understand conceptual learning. You will learn what ML is, how it works, its types, and real-world examples.
26.1 What is Machine Learning?
Machine Learning (ML) is a branch of Artificial Intelligence that allows computers to learn patterns from data and make decisions without being explicitly programmed.
🎯 Why ML is Popular?
- ✔ Automates tasks
- ✔ Identifies complex patterns
- ✔ Makes predictions (future trends)
- ✔ Used in almost every industry
🧠 How ML Works (Simple Workflow)
| Step | Description |
|---|---|
| 1. Collect Data | Gather training data (examples). |
| 2. Train Model | Let the algorithm learn patterns. |
| 3. Test Model | Check how accurately it works. |
| 4. Predict Output | Use the trained model to make predictions. |
26.2 Data Preparation Concepts
Machine Learning works only when the data is clean and organized. This step is called Data Preprocessing.
✔ Key Steps in Data Preparation
- ✔ Handling missing values
- ✔ Converting text to numbers
- ✔ Splitting data into training & testing
- ✔ Normalizing or scaling values
26.3 Supervised Learning (Simple Explanation)
In Supervised Learning, the model learns using labeled data, meaning the input already has correct answers.
📘 Example
✔ Types of Supervised Learning
- Regression – Predict numbers
(House price, temperature) - Classification – Predict categories
(Spam or Not Spam, Yes or No)
26.4 Unsupervised Learning (Easy Examples)
In Unsupervised Learning, the model is given data without labels. It tries to find hidden patterns on its own.
✔ Most Common Unsupervised Technique
- Clustering – Grouping similar items
✔ Where It Is Used?
- ✔ Market segmentation
- ✔ Product recommendation
- ✔ Fraud detection
26.5 Real-World ML Use Cases
Machine Learning is everywhere. Here are simple, real-world examples you see daily:
- ✔ YouTube video recommendations
- ✔ Face unlock on mobile phones
- ✔ Self-driving car route decisions
- ✔ Detecting fake transactions in banks
- ✔ Voice assistants (Siri, Alexa)
💬 Simple Example
🎓 Module 26 : Intro to Python Machine Learning (Concept Only) Successfully Completed
You have successfully completed this module of Python for Cybersecurity.
Keep building your expertise step by step — Learn Next Module →
🧠 Python Artificial Intelligence (AI) – Beginner-Friendly Concept
This module gives a simple and clear introduction to Artificial Intelligence (AI) using Python. No mathematics or coding depth — just conceptual understanding for beginners.
27.1 What is Artificial Intelligence?
Artificial Intelligence (AI) is the ability of machines to perform tasks that typically require human intelligence. AI systems can think, learn, decide, and solve problems.
🎯 What Can AI Do?
- ✔ Recognize images & faces
- ✔ Predict outcomes (sales, weather, prices)
- ✔ Understand and generate human language
- ✔ Drive cars autonomously
- ✔ Recommend videos, songs, and products
27.2 Categories of AI (ANI, AGI, ASI)
AI is divided into three major categories based on intelligence level:
| Type | Description | Examples |
|---|---|---|
| ANI (Artificial Narrow Intelligence) | AI that performs only one specific task. | Alexa, Google Assistant, Face Unlock |
| AGI (Artificial General Intelligence) | AI that can think & learn like humans. | Not fully developed yet |
| ASI (Artificial Super Intelligence) | AI that surpasses human intelligence. | Only theoretical |
27.3 Python's Role in AI
Python is the most popular language for Artificial Intelligence because it is:
- ✔ Easy to learn and write
- ✔ Has powerful AI & ML libraries
- ✔ Huge community support
- ✔ Ideal for rapid prototyping
🔬 Popular Python Libraries for AI
- TensorFlow – Deep Learning
- Keras – Easy Neural Networks
- PyTorch – Advanced ML models
- Scikit-Learn – Simple ML algorithms
- NLTK / spaCy – Natural Language Processing
27.4 Real-Life AI Applications
Artificial Intelligence is used almost everywhere in the modern world.
- ✔ Self-driving cars analyzing road conditions
- ✔ Medical diagnosis systems predicting diseases
- ✔ Virtual assistants answering questions
- ✔ Chatbots providing customer support
- ✔ E-commerce recommendations based on past purchases
- ✔ Banking fraud detection systems
27.5 Ethics of AI (Simple Explanation)
As AI becomes powerful, ethical considerations are extremely important to ensure AI is used responsibly and safely.
⚖️ Key Ethical Concerns
- ❌ Bias in AI decisions
- ❌ Privacy issues
- ❌ Job displacement due to automation
- ❌ Misuse of AI for harmful activities
✔ Ethical AI Practices
- ✔ Transparent algorithms
- ✔ Fair and unbiased datasets
- ✔ Privacy protection
- ✔ Human oversight and accountability
🎓 Module 27 : Intro to Python Artificial Intelligence (AI Concept) Successfully Completed
You have successfully completed this module of Python for Cybersecurity.
Keep building your expertise step by step — Learn Next Module →
🔧 Python Functions – Easy & Powerful
Functions are reusable blocks of code that help you organize and simplify your Python programs. This module explains functions in a very simple, beginner-friendly way with examples.
28.1 What is a Function?
A function is a block of code that runs only when called. Functions help reduce repetition and make programs cleaner.
✔ Basic Function Example
def greet():
print("Hello, welcome to Python!")
greet()
28.2 Defining Your Own Functions
You can create a function using the def keyword.
✔ Example: Simple Addition Function
def add_numbers():
print(10 + 20)
add_numbers()
28.3 Arguments & Parameters (Simple Explanation)
Functions can take inputs called arguments. These allow functions to work with different values.
🎯 Example: Function with Arguments
def greet(name):
print("Hello", name)
greet("John")
greet("Ayesha")
✔ Return Statement Explained
def add(a, b):
return a + b
result = add(5, 7)
print(result)
28.4 Lambda Functions (One-line Functions)
A lambda function is a small, anonymous (no name) function written in one line.
✔ Example: One-line Add Function
add = lambda x, y: x + y
print(add(5, 3))
✔ Use Cases of Lambda Functions
- ✔ Small calculations
- ✔ Sorting lists
- ✔ Used with map(), filter(), reduce()
28.5 Recursion Explained Slowly
Recursion means a function calling itself. It's used to solve problems that can be broken into smaller sub-problems.
✔ Example: Simple Recursive Countdown
def countdown(n):
if n == 0:
print("Blast Off!")
else:
print(n)
countdown(n - 1)
countdown(5)
Functions help you write cleaner, smarter, and reusable code — making Python more powerful and easier to manage.
🎓 Module 28 : Functions in Python (Easy & Powerful) Successfully Completed
You have successfully completed this module of Python for Cybersecurity.
Keep building your expertise step by step — Learn Next Module →