Python Tutorial with examples
🐍 Python Syllabus (Beginner → Advanced)
1. Beginner Level
- Introduction
- What is Python, installation, IDEs
- Running Python scripts
- Basics
- Syntax, keywords, indentation
- Variables & data types
- Input/Output
- Operators (arithmetic, relational, logical)
- Control Flow
- Conditional statements (
if,elif,else) - Loops (
for,while) - Loop control (
break,continue,pass)
- Conditional statements (
- Collections
- Lists, tuples, sets, dictionaries
- Indexing, slicing, methods
2. Intermediate Level
- Functions
- Defining functions, arguments, return values
- Default & keyword arguments
- Lambda functions
- Modules & Packages
- Importing modules
- Standard libraries overview
- Error Handling
- Exceptions (
try,except,finally) - Custom exceptions
- Exceptions (
- File Handling
- Reading/writing files
- Working with CSV, JSON
- Object-Oriented Programming
- Classes & objects
- Constructors, methods
- Inheritance, polymorphism, encapsulation
3. Advanced Level
- Iterators & Generators
iter(),next()yieldkeyword
- Decorators
- Function decorators
- Class decorators
- Recursion
- Recursive functions
- Applications (factorial, Fibonacci, Tower of Hanoi)
- Data Structures & Algorithms
- Searching & sorting
- Linked lists, stacks, queues
- Advanced OOP
- Abstract classes
- Multiple inheritance
- Modules for Productivity
os,sys,datetime,collectionsre(regular expressions)
- Python for Automation
- Web scraping (
requests,BeautifulSoup) - Scripting tasks
- Web scraping (
- Python for Data Handling
- NumPy, Pandas basics
- Data visualization (Matplotlib, Seaborn)
4. Expert / Specialized Topics
- Concurrency
- Multithreading & multiprocessing
- Async programming (
asyncio)
- Advanced Libraries
- Flask/Django (web development)
- TensorFlow/PyTorch (machine learning)
- Testing
- Unit testing (
unittest,pytest)
- Unit testing (
- Deployment
- Virtual environments
- Packaging & distribution
- Best Practices
- Code style (PEP 8)
- Documentation
- Version control (Git)
1. What is Python?
- High-level language: Easy to read and write, close to human language.
- Interpreted: Code runs line by line, no need for compilation.
- Versatile: Used in web development, data science, AI, automation, and more.
- Cross-platform: Works on Windows, macOS, and Linux.
2. Installing Python
Windows
- Go to python.org/downloads.
- Download the latest version (Python 3.x).
- Run the installer → check “Add Python to PATH”.
- Click Install Now.
- Verify installation:
orpython --versionpython
macOS
- Python 3 may already be installed.
- To install latest:
(requires Homebrew).brew install python - Verify:
python3 --version
Linux
Most distros ship with Python.
To install/update:
sudo apt update sudo apt install python3Verify:
python3 --version
3. Setting Up IDEs
Popular IDEs for Python:
- VS Code: Lightweight, extensions for Python debugging, linting.
- PyCharm: Full-featured IDE, great for large projects.
- Jupyter Notebook: Ideal for data science, interactive coding.
- IDLE: Comes bundled with Python, simple for beginners.
Steps:
- Install your chosen IDE.
- Configure Python interpreter (point IDE to your installed Python).
- Add extensions/plugins (e.g., Python extension in VS Code).
4. Running Python Scripts
Method 1: Command Line
- Save file as
hello.py:print("Hello, World!") - Run:
python hello.py
Method 2: IDE
- Open file in VS Code/PyCharm.
- Click Run or use shortcut (
Shift+F10in PyCharm,Ctrl+F5in VS Code).
Method 3: Interactive Mode
- Open terminal → type:
python - Enter commands directly:
>>> print("Hello")
Perfect 👌 Let’s build Section 1: Python Fundamentals in a detailed, beginner-friendly way — step by step with examples.
This can also help you if you're creating YouTube tutorials or an ebook (like your JavaScript ebook idea 😉).
🐍 Section 1: Python Fundamentals
1️⃣ Syntax (Basic Python Programming Syntax)
🔹 What is Syntax?
Syntax means rules of writing code in a programming language.
Python is:
Simple
Readable
Uses indentation (very important!)
🔹 First Python Program
print("Hello, World!")
Output:
Hello, World!
🔹 Indentation (Very Important in Python)
Python uses indentation instead of {}.
if 5 > 2:
print("Five is greater than two")
❌ Wrong:
if 5 > 2:
print("Five is greater than two") # IndentationError
✔ Indentation defines blocks of code.
🔹 Python is Case-Sensitive
name = "Hari"
Name = "Mohan"
print(name) # Hari
print(Name) # Mohan
These are two different variables.
2️⃣ Variables
🔹 What is a Variable?
A variable is a container to store data.
🔹 Creating Variables
name = "Hari"
age = 25
salary = 50000.50
No need to declare type explicitly.
🔹 Rules for Naming Variables
✔ Can contain:
Letters (a-z, A-Z)
Numbers (0-9)
Underscore (_)
❌ Cannot:
Start with number
Use special characters
Use Python keywords
Valid:
user_name = "Hari"
age1 = 25
Invalid:
1name = "Hari" # Error
user-name = "Hari" # Error
🔹 Multiple Assignment
a, b, c = 1, 2, 3
print(a, b, c)
🔹 Dynamic Typing
x = 10
x = "Hari"
Python allows changing type dynamically.
3️⃣ Strings
🔹 What is a String?
A string is a sequence of characters.
name = "Hari"
message = 'Hello World'
🔹 Multi-line Strings
text = """This is
a multi-line
string"""
🔹 String Operations
Concatenation
first = "Hari"
last = "Mohan"
full = first + " " + last
print(full)
Repetition
print("Hi " * 3)
Output:
Hi Hi Hi
String Length
print(len("Hari"))
Indexing
name = "Python"
print(name[0]) # P
print(name[-1]) # n
Slicing
print(name[0:3]) # Pyt
Useful String Methods
text = "python"
print(text.upper())
print(text.capitalize())
print(text.replace("p", "P"))
4️⃣ Numbers
Python mainly has:
intfloatcomplex
🔹 Integers
x = 10
y = -5
🔹 Float
price = 99.99
pi = 3.14
🔹 Arithmetic Operators
a = 10
b = 3
print(a + b) # 13
print(a - b) # 7
print(a * b) # 30
print(a / b) # 3.333
print(a // b) # 3
print(a % b) # 1
print(a ** b) # 1000
5️⃣ Booleans
🔹 Boolean Type
Boolean has only two values:
TrueFalse
is_active = True
is_admin = False
🔹 Comparison Operators
print(5 > 3) # True
print(5 == 3) # False
print(5 != 3) # True
🔹 Truthy and Falsy Values
🔻 Falsy Values:
0""(empty string)NoneFalse[]{}
if "":
print("True")
else:
print("False") # This will run
6️⃣ Constants
Python doesn't have built-in constants, but by convention we use:
🔹 UPPERCASE variable names
PI = 3.14159
MAX_USERS = 100
Python won’t stop you from changing it, but it signals:
👉 “Do not modify”
7️⃣ Comments
Comments are notes for developers.
🔹 Single-line Comment
# This is a comment
print("Hello")
🔹 Multi-line Comment
"""
This is a
multi-line comment
"""
8️⃣ Type Conversion (Type Casting)
Type conversion means changing one data type into another.
🔹 Convert String to Integer
age = "25"
age = int(age)
print(age + 5) # 30
🔹 Convert Integer to String
num = 100
text = str(num)
print("Number is " + text)
🔹 Convert to Float
x = "10.5"
y = float(x)
print(y)
🔹 Check Type
x = 10
print(type(x))
🔥 Mini Practice
name = input("Enter your name: ")
age = int(input("Enter your age: "))
print("Hello", name)
print("Next year you will be", age + 1)
📌 Summary
| Concept | What You Learned |
|---|---|
| Syntax | Indentation, case sensitivity |
| Variables | Dynamic typing |
| Strings | Indexing, slicing, methods |
| Numbers | int, float, operators |
| Booleans | True/False, truthy/falsy |
| Constants | UPPERCASE convention |
| Comments | Code documentation |
| Type Conversion | int(), str(), float() |
🐍 Section 2: Operators in Python
Operators are symbols used to perform operations on variables and values.
Example:
5 + 3
Here + is an operator.
1️⃣ Arithmetic Operators
Used to perform mathematical calculations.
🔹 List of Arithmetic Operators
| Operator | Meaning | Example |
|---|---|---|
+ | Addition | 5 + 2 |
- | Subtraction | 5 - 2 |
* | Multiplication | 5 * 2 |
/ | Division (float result) | 5 / 2 |
// | Floor Division | 5 // 2 |
% | Modulus (remainder) | 5 % 2 |
** | Exponent (power) | 5 ** 2 |
🔹 Addition (+)
a = 10
b = 5
print(a + b)
Output:
15
🔹 Subtraction (-)
print(10 - 3)
Output:
7
🔹 Multiplication (*)
print(4 * 3)
Output:
12
🔹 Division (/)
Always returns float.
print(10 / 2) # 5.0
print(5 / 2) # 2.5
🔹 Floor Division (//)
Removes decimal part.
print(5 // 2) # 2
🔹 Modulus (%)
Returns remainder.
print(10 % 3) # 1
Common use:
Check even/odd
num = 4
if num % 2 == 0:
print("Even")
🔹 Exponent (**)
print(2 ** 3) # 8
🔹 Operator Precedence (Important)
print(2 + 3 * 4)
Output:
14
Because:
Multiplication runs before addition.
Use parentheses:
print((2 + 3) * 4)
Output:
20
2️⃣ Assignment Operators
Used to assign values to variables.
🔹 Basic Assignment (=)
x = 10
🔹 Compound Assignment Operators
| Operator | Meaning | Example |
|---|---|---|
+= | Add and assign | x += 5 |
-= | Subtract and assign | x -= 5 |
*= | Multiply and assign | x *= 5 |
/= | Divide and assign | x /= 5 |
//= | Floor divide assign | x //= 5 |
%= | Modulus assign | x %= 5 |
**= | Power assign | x **= 2 |
🔹 Example
x = 10
x += 5
print(x) # 15
Equivalent to:
x = x + 5
🔹 More Examples
x = 10
x -= 3
print(x) # 7
x *= 2
print(x) # 14
x /= 2
print(x) # 7.0
3️⃣ Comparison Operators
Used to compare two values.
Return type: Boolean (True or False)
🔹 List of Comparison Operators
| Operator | Meaning |
|---|---|
== | Equal to |
!= | Not equal |
> | Greater than |
< | Less than |
>= | Greater than or equal |
<= | Less than or equal |
🔹 Examples
print(5 == 5) # True
print(5 != 3) # True
print(5 > 3) # True
print(5 < 3) # False
print(5 >= 5) # True
print(5 <= 3) # False
🔹 Comparing Strings
print("apple" == "apple") # True
print("apple" > "banana") # False
Comparison is based on ASCII / Unicode values.
🔹 Chained Comparisons (Python Special Feature)
x = 10
print(5 < x < 20)
Output:
True
Equivalent to:
5 < x and x < 20
4️⃣ Logical Operators
Used to combine multiple conditions.
🔹 List of Logical Operators
| Operator | Meaning |
|---|---|
and | True if both conditions are True |
or | True if at least one condition is True |
not | Reverses condition |
🔹 Logical AND
age = 25
has_license = True
if age > 18 and has_license:
print("You can drive")
Both conditions must be True.
🔹 Logical OR
is_admin = False
is_superuser = True
if is_admin or is_superuser:
print("Access granted")
At least one must be True.
🔹 Logical NOT
is_logged_in = False
if not is_logged_in:
print("Please login")
not False → True
🔥 Truth Table
AND
| A | B | A and B |
|---|---|---|
| T | T | T |
| T | F | F |
| F | T | F |
| F | F | F |
OR
| A | B | A or B |
|---|---|---|
| T | T | T |
| T | F | T |
| F | T | T |
| F | F | F |
NOT
| A | not A |
|---|---|
| True | False |
| False | True |
🔥 Short-Circuiting (Advanced Concept)
Python stops evaluation early.
Example:
False and print("Hello")
Nothing prints because:
First condition is False
AND already False → stops
🔥 Practical Example
username = "hari"
password = "1234"
if username == "hari" and password == "1234":
print("Login successful")
else:
print("Invalid credentials")
📌 Summary
| Category | Purpose |
|---|---|
| Arithmetic | Math operations |
| Assignment | Store & update values |
| Comparison | Compare values |
| Logical | Combine conditions |
Perfect 👌
Now let’s build Section 3: Control Flow in Python — detailed, structured, beginner → intermediate level with examples and explanations.
🐍 Section 3: Control Flow
Control flow allows your program to:
Make decisions
Repeat actions
Control execution order
1️⃣ if…else Statement
Used to execute code based on a condition.
🔹 Basic Syntax
if condition:
# code block
🔹 Simple Example
age = 20
if age >= 18:
print("You are an adult")
If condition is True, block executes.
🔹 if…else
age = 16
if age >= 18:
print("Adult")
else:
print("Minor")
If condition is False → else runs.
🔹 if…elif…else
Used when checking multiple conditions.
marks = 75
if marks >= 90:
print("Grade A")
elif marks >= 70:
print("Grade B")
elif marks >= 50:
print("Grade C")
else:
print("Fail")
Python checks conditions from top to bottom.
🔹 Nested if
age = 25
has_license = True
if age >= 18:
if has_license:
print("You can drive")
else:
print("You need a license")
2️⃣ Ternary Operator (Conditional Expression)
Makes code shorter and cleaner.
🔹 Syntax
value_if_true if condition else value_if_false
🔹 Example
Normal way:
age = 20
if age >= 18:
result = "Adult"
else:
result = "Minor"
Ternary way:
age = 20
result = "Adult" if age >= 18 else "Minor"
print(result)
🔹 Another Example
num = 10
print("Even") if num % 2 == 0 else print("Odd")
⚠️ Best practice:
Use ternary only for simple conditions.
3️⃣ for Loop with range()
Used when number of iterations is known.
🔹 Basic Syntax
for variable in range(start, stop, step):
# code block
🔹 range() Variations
1. Only stop
for i in range(5):
print(i)
Output:
0
1
2
3
4
Default start = 0
2. Start and Stop
for i in range(1, 6):
print(i)
Output:
1
2
3
4
5
3. Start, Stop, Step
for i in range(0, 10, 2):
print(i)
Output:
0
2
4
6
8
🔹 Loop Through String
name = "Hari"
for char in name:
print(char)
🔹 Example: Sum of First 5 Numbers
total = 0
for i in range(1, 6):
total += i
print(total)
Output:
15
4️⃣ while Loop
Used when number of iterations is not fixed.
Runs as long as condition is True.
🔹 Basic Syntax
while condition:
# code block
🔹 Example
count = 1
while count <= 5:
print(count)
count += 1
⚠️ Important:
Always update condition variable.
Otherwise → Infinite Loop.
🔹 Infinite Loop Example
while True:
print("Running...")
Used in:
Game loops
Servers
Continuous processes
5️⃣ break Statement
Used to exit loop immediately.
🔹 Example with for
for i in range(10):
if i == 5:
break
print(i)
Output:
0
1
2
3
4
Loop stops at 5.
🔹 Example with while
count = 1
while count <= 10:
if count == 6:
break
print(count)
count += 1
6️⃣ continue Statement
Skips current iteration and moves to next.
🔹 Example
for i in range(5):
if i == 2:
continue
print(i)
Output:
0
1
3
4
When i == 2 → skipped.
🔹 Practical Example: Print Only Even Numbers
for i in range(10):
if i % 2 != 0:
continue
print(i)
🔥 break vs continue
| Statement | What it Does |
|---|---|
| break | Stops entire loop |
| continue | Skips current iteration |
🔥 for vs while
| for loop | while loop |
|---|---|
| Known iterations | Unknown iterations |
| Uses range() | Uses condition |
| Cleaner for counting | Good for dynamic cases |
🔥 Real-world Example
Password check:
correct_password = "1234"
while True:
password = input("Enter password: ")
if password == correct_password:
print("Access Granted")
break
else:
print("Try again")
📌 Summary
| Concept | Purpose |
|---|---|
| if / else | Decision making |
| Ternary | Short conditional |
| for loop | Fixed repetitions |
| while loop | Condition-based repetition |
| break | Exit loop |
| continue | Skip iteration |
Perfect 👌
Let’s understand pass statement in Python in detail.
🐍 The pass Statement in Python
🔹 What is pass?
pass is a null statement.
It does nothing.
It is used as a placeholder when Python requires a statement but you don’t want to write code yet.
🔹 Why Do We Need pass?
Python does not allow empty code blocks.
This ❌ will cause an error:
if True:
Error:
IndentationError: expected an indented block
So we use pass to avoid syntax error.
1️⃣ Using pass in if Statement
age = 18
if age >= 18:
pass
This runs without error, but does nothing.
2️⃣ Using pass in Loops
Sometimes we create a loop but implement logic later.
for i in range(5):
pass
Loop runs but no output.
Example: Empty while Loop
while True:
pass
⚠️ Warning: This creates an infinite loop that does nothing (uses CPU).
3️⃣ Using pass in Functions
When defining a function structure first:
def my_function():
pass
Useful when:
Designing structure first
Writing skeleton code
Planning large projects
4️⃣ Using pass in Classes
class Person:
pass
Creates an empty class.
5️⃣ Practical Real-world Example
Imagine you're building a login system and want to implement later:
username = "admin"
if username == "admin":
pass # Add admin logic later
else:
print("Access Denied")
🔥 pass vs continue vs break
| Statement | What it Does |
|---|---|
pass | Does nothing |
continue | Skips current loop iteration |
break | Stops loop completely |
Example to Compare
for i in range(5):
if i == 2:
pass
print(i)
Output:
0
1
2
3
4
Because pass does nothing.
Now with continue:
for i in range(5):
if i == 2:
continue
print(i)
Output:
0
1
3
4
🔥 When Should You Use pass?
✔ While designing code structure
✔ Creating empty functions/classes
✔ Avoiding syntax errors
✔ Planning logic later
❌ Not for skipping logic permanently
📌 Summary
pass= placeholderUsed when block cannot be empty
Common in if, loops, functions, classes
Does absolutely nothing
🐍 Python Lists
🔹 What is a List?
A list is a collection that:
Stores multiple values
Is ordered
Is changeable (mutable)
Allows duplicate values
🔹 Creating a List
numbers = [1, 2, 3, 4, 5]
names = ["Hari", "Mohan", "Python"]
mixed = [10, "Hello", True, 5.5]
🔹 Accessing List Elements
Indexing
names = ["Hari", "Mohan", "Python"]
print(names[0]) # Hari
print(names[-1]) # Python
Slicing
numbers = [1, 2, 3, 4, 5]
print(numbers[1:4]) # [2, 3, 4]
🔹 Changing List Elements
numbers = [1, 2, 3]
numbers[0] = 100
print(numbers) # [100, 2, 3]
🔹 Loop Through List
for item in numbers:
print(item)
📌 Important List Methods
1️⃣ append()
Adds element at the end.
fruits = ["apple", "banana"]
fruits.append("mango")
print(fruits)
Output:
['apple', 'banana', 'mango']
2️⃣ insert()
Insert element at specific index.
fruits = ["apple", "banana"]
fruits.insert(1, "orange")
print(fruits)
Output:
['apple', 'orange', 'banana']
3️⃣ extend()
Adds multiple elements (another list).
a = [1, 2]
b = [3, 4]
a.extend(b)
print(a)
Output:
[1, 2, 3, 4]
4️⃣ remove()
Removes first matching value.
numbers = [1, 2, 3, 2]
numbers.remove(2)
print(numbers)
Output:
[1, 3, 2]
5️⃣ pop()
Removes element by index (default: last).
numbers = [10, 20, 30]
numbers.pop()
print(numbers)
Output:
[10, 20]
Remove specific index:
numbers.pop(0)
6️⃣ clear()
Removes all elements.
numbers = [1, 2, 3]
numbers.clear()
print(numbers) # []
7️⃣ index()
Returns index of first match.
names = ["Hari", "Mohan", "Python"]
print(names.index("Mohan"))
Output:
1
8️⃣ count()
Counts occurrences.
numbers = [1, 2, 2, 3, 2]
print(numbers.count(2))
Output:
3
9️⃣ sort()
Sorts list (ascending by default).
numbers = [4, 1, 3, 2]
numbers.sort()
print(numbers)
Output:
[1, 2, 3, 4]
Descending:
numbers.sort(reverse=True)
🔟 reverse()
Reverses list order.
numbers = [1, 2, 3]
numbers.reverse()
print(numbers)
Output:
[3, 2, 1]
1️⃣1️⃣ copy()
Creates shallow copy.
a = [1, 2, 3]
b = a.copy()
print(b)
🔥 Built-in Functions Useful with Lists
len()
print(len([1, 2, 3]))
max() / min()
numbers = [10, 20, 5]
print(max(numbers)) # 20
print(min(numbers)) # 5
sum()
numbers = [1, 2, 3]
print(sum(numbers)) # 6
🔥 Nested Lists
matrix = [
[1, 2, 3],
[4, 5, 6]
]
print(matrix[0][1]) # 2
🔥 List Comprehension (Important)
Short way to create lists.
Normal way:
squares = []
for i in range(5):
squares.append(i * i)
List comprehension:
squares = [i * i for i in range(5)]
print(squares)
Output:
[0, 1, 4, 9, 16]
🔥 Practical Example
Remove even numbers:
numbers = [1, 2, 3, 4, 5, 6]
odd_numbers = [n for n in numbers if n % 2 != 0]
print(odd_numbers)
📌 Summary of List Methods
| Method | Purpose |
|---|---|
| append() | Add one element |
| insert() | Add at position |
| extend() | Add multiple elements |
| remove() | Remove by value |
| pop() | Remove by index |
| clear() | Remove all |
| index() | Find position |
| count() | Count occurrences |
| sort() | Sort list |
| reverse() | Reverse order |
| copy() | Copy list. |
🐍 Strings in Python
🔹 What is a String?
A string is a sequence of characters enclosed in quotes.
name = "Hari"
message = 'Hello World'
Python supports:
Single quotes
' 'Double quotes
" "Triple quotes
""" """(multi-line)
🔹 Multi-line String
text = """This is
a multi-line
string"""
🔹 String Characteristics
✔ Ordered
✔ Immutable (Cannot change directly)
✔ Supports indexing and slicing
🔹 Indexing
name = "Python"
print(name[0]) # P
print(name[-1]) # n
🔹 Slicing
print(name[0:3]) # Pyt
print(name[:4]) # Pyth
print(name[2:]) # thon
🔥 String is Immutable
text = "Hello"
text[0] = "h" # ❌ Error
Instead:
text = "Hello"
text = "h" + text[1:]
print(text)
📌 Important String Methods
1️⃣ upper()
Convert to uppercase.
text = "python"
print(text.upper())
Output:
PYTHON
2️⃣ lower()
text = "PYTHON"
print(text.lower())
3️⃣ capitalize()
Capitalizes first letter.
print("python".capitalize())
4️⃣ title()
Capitalizes each word.
print("hello world".title())
5️⃣ strip()
Removes spaces from both sides.
text = " hello "
print(text.strip())
lstrip() / rstrip()
text = " hello "
print(text.lstrip())
print(text.rstrip())
6️⃣ replace()
Replace substring.
text = "I love Java"
print(text.replace("Java", "Python"))
7️⃣ split()
Split string into list.
text = "apple,banana,mango"
print(text.split(","))
Output:
['apple', 'banana', 'mango']
8️⃣ join()
Join list into string.
words = ["Hello", "World"]
print(" ".join(words))
9️⃣ find()
Returns index or -1.
text = "Python"
print(text.find("th"))
🔟 index()
Same as find but gives error if not found.
print(text.index("th"))
1️⃣1️⃣ count()
Counts occurrences.
print("banana".count("a"))
1️⃣2️⃣ startswith() / endswith()
text = "Python Programming"
print(text.startswith("Python"))
print(text.endswith("ing"))
1️⃣3️⃣ isalpha()
print("Python".isalpha()) # True
print("Python123".isalpha()) # False
1️⃣4️⃣ isdigit()
print("123".isdigit())
print("12a3".isdigit())
1️⃣5️⃣ isalnum()
print("Python123".isalnum())
1️⃣6️⃣ isspace()
print(" ".isspace())
1️⃣7️⃣ format()
name = "Hari"
age = 25
print("My name is {} and I am {} years old".format(name, age))
🔥 f-Strings (Recommended Modern Way)
name = "Hari"
age = 25
print(f"My name is {name} and I am {age} years old")
🔥 Escape Characters
| Escape | Meaning |
|---|---|
| \n | New line |
| \t | Tab |
| \ | Backslash |
| " | Double quote |
Example:
print("Hello\nWorld")
🔥 String Concatenation
first = "Hari"
last = "Mohan"
print(first + " " + last)
🔥 String Multiplication
print("Hi " * 3)
🔥 Iterating Over String
for char in "Python":
print(char)
🔥 Practical Example
Check palindrome:
text = "madam"
if text == text[::-1]:
print("Palindrome")
📌 Summary of Important String Methods
| Method | Purpose |
|---|---|
| upper() | Uppercase |
| lower() | Lowercase |
| capitalize() | First letter uppercase |
| title() | Capitalize each word |
| strip() | Remove spaces |
| replace() | Replace text |
| split() | Convert to list |
| join() | Convert list to string |
| find() | Find index |
| count() | Count occurrences |
| startswith() | Check prefix |
| endswith() | Check suffix |
| isalpha() | Letters only |
| isdigit() | Digits only |
| isalnum() | Alphanumeric |
🐍 Dictionary in Python
🔹 What is a Dictionary?
A dictionary is:
A collection of key–value pairs
Ordered (Python 3.7+)
Mutable (can change)
Keys must be unique
Keys must be immutable (string, number, tuple)
🔹 Creating a Dictionary
student = {
"name": "Hari",
"age": 25,
"course": "Python"
}
🔹 Accessing Values
Using Key
print(student["name"])
⚠️ If key doesn’t exist → Error
Using get() (Safe Way)
print(student.get("name"))
print(student.get("marks")) # None (no error)
🔹 Dictionary is Mutable
student["age"] = 26
print(student)
🔹 Adding New Key
student["city"] = "Bangalore"
🔹 Removing Items
1️⃣ pop()
Removes specific key.
student.pop("age")
2️⃣ popitem()
Removes last inserted item.
student.popitem()
3️⃣ del
del student["course"]
4️⃣ clear()
student.clear()
📌 Important Dictionary Methods
1️⃣ keys()
Returns all keys.
student = {"name": "Hari", "age": 25}
print(student.keys())
Output:
dict_keys(['name', 'age'])
2️⃣ values()
Returns all values.
print(student.values())
3️⃣ items()
Returns key-value pairs as tuples.
print(student.items())
Output:
dict_items([('name', 'Hari'), ('age', 25)])
4️⃣ update()
Updates dictionary with another dictionary.
student = {"name": "Hari", "age": 25}
student.update({"age": 30, "city": "Delhi"})
print(student)
5️⃣ setdefault()
Returns value if key exists, otherwise inserts key with default value.
student = {"name": "Hari"}
student.setdefault("age", 25)
print(student)
6️⃣ copy()
Creates shallow copy.
new_student = student.copy()
🔥 Looping Through Dictionary
Loop Through Keys
for key in student:
print(key)
Loop Through Values
for value in student.values():
print(value)
Loop Through Key-Value
for key, value in student.items():
print(key, value)
🔥 Nested Dictionary
students = {
"student1": {"name": "Hari", "age": 25},
"student2": {"name": "Mohan", "age": 22}
}
print(students["student1"]["name"])
🔥 Dictionary Comprehension (Important)
squares = {x: x*x for x in range(5)}
print(squares)
Output:
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
🔥 Check if Key Exists
if "name" in student:
print("Key exists")
🔥 Difference Between dict vs list
| Feature | List | Dictionary |
|---|---|---|
| Access by | Index | Key |
| Syntax | [] | {} |
| Stores | Values | Key-Value pairs |
🔥 Practical Example
Count frequency of characters:
text = "banana"
frequency = {}
for char in text:
frequency[char] = frequency.get(char, 0) + 1
print(frequency)
Output:
{'b': 1, 'a': 3, 'n': 2}
📌 Summary of Important Dictionary Methods
| Method | Purpose |
|---|---|
| get() | Safe access |
| keys() | Get all keys |
| values() | Get all values |
| items() | Get key-value pairs |
| update() | Update dictionary |
| pop() | Remove by key |
| popitem() | Remove last item |
| clear() | Remove all |
| copy() | Copy dictionary |
| setdefault() | Insert default value |
🐍 Tuple in Python
🔹 What is a Tuple?
A tuple is:
An ordered collection of elements
Immutable (cannot change after creation)
Allows duplicate values
Can store different data types
🔹 Creating a Tuple
Basic Tuple
numbers = (1, 2, 3, 4)
numbers = (1, 2, 3, 4)
Without Parentheses (Tuple Packing)
numbers = 1, 2, 3
print(type(numbers))
numbers = 1, 2, 3
print(type(numbers))
Output:
<class 'tuple'>
Single Element Tuple (Important ⚠️)
t = (5,)
t = (5,)
Without comma:
t = (5) # This is int, not tuple
🔹 Accessing Tuple Elements
Indexing
t = (10, 20, 30)
print(t[0]) # 10
print(t[-1]) # 30
t = (10, 20, 30)
print(t[0]) # 10
print(t[-1]) # 30
Slicing
t = (1, 2, 3, 4, 5)
print(t[1:4]) # (2, 3, 4)
t = (1, 2, 3, 4, 5)
print(t[1:4]) # (2, 3, 4)
🔥 Tuple is Immutable
t = (1, 2, 3)
t[0] = 100 # ❌ Error
t = (1, 2, 3)
t[0] = 100 # ❌ Error
You cannot modify, add, or remove elements.
🔹 Looping Through Tuple
t = (1, 2, 3)
for item in t:
print(item)
t = (1, 2, 3)
for item in t:
print(item)
📌 Tuple Methods (Very Few)
Tuple has only 2 built-in methods:
1️⃣ count()
Counts occurrences.
t = (1, 2, 2, 3, 2)
print(t.count(2))
Output:
3
2️⃣ index()
Returns index of first match.
t = (10, 20, 30)
print(t.index(20))
Output:
1
🔥 Tuple Packing and Unpacking (Important)
Packing
person = ("Hari", 25, "Developer")
person = ("Hari", 25, "Developer")
Unpacking
name, age, profession = person
print(name)
print(age)
print(profession)
name, age, profession = person
print(name)
print(age)
print(profession)
Using * (Star Unpacking)
numbers = (1, 2, 3, 4, 5)
a, *b, c = numbers
print(a) # 1
print(b) # [2, 3, 4]
print(c) # 5
numbers = (1, 2, 3, 4, 5)
a, *b, c = numbers
print(a) # 1
print(b) # [2, 3, 4]
print(c) # 5
🔥 Tuple vs List
| Feature | Tuple | List |
|---|---|---|
| Syntax | () | [] |
| Mutable | ❌ No | ✔ Yes |
| Performance | Faster | Slower |
| Memory | Less | More |
| Methods | 2 | Many |
🔥 Why Use Tuple?
✔ When data should not change
✔ Faster performance
✔ Can be used as dictionary keys
✔ Safe data storage
🔥 Tuple as Dictionary Key
location = {(10, 20): "Point A"}
print(location[(10, 20)])
location = {(10, 20): "Point A"}
print(location[(10, 20)])
Works because tuple is immutable.
🔥 Nested Tuple
t = ((1, 2), (3, 4))
print(t[0][1]) # 2
t = ((1, 2), (3, 4))
print(t[0][1]) # 2
🔥 Convert Tuple ↔ List
Tuple to List
t = (1, 2, 3)
l = list(t)
t = (1, 2, 3)
l = list(t)
List to Tuple
l = [1, 2, 3]
t = tuple(l)
l = [1, 2, 3]
t = tuple(l)
🔥 Practical Example
Swap two variables (Python special feature):
a = 10
b = 20
a, b = b, a
print(a, b)
Behind the scenes → Tuple packing & unpacking.
📌 Summary
Tuple = ordered + immutable
Uses ()
Allows duplicates
Faster than list
Methods: count(), index()
Supports unpacking
Tuple = ordered + immutable
Uses ()
Allows duplicates
Faster than list
Methods: count(), index()
Supports unpacking
🐍 Sets in Python
🔹 What is a Set?
A set is:
An unordered collection
Contains unique elements (no duplicates)
Mutable (can add/remove elements)
Written using
{}
🔹 Creating a Set
numbers = {1, 2, 3, 4}
print(type(numbers))
numbers = {1, 2, 3, 4}
print(type(numbers))
🔹 Duplicate Values Removed Automatically
nums = {1, 2, 2, 3, 3, 4}
print(nums)
nums = {1, 2, 2, 3, 3, 4}
print(nums)
Output:
{1, 2, 3, 4}
🔹 Empty Set (Important ⚠️)
s = set() # Correct
s = set() # Correct
❌ Wrong:
s = {} # This creates dictionary
🔥 Set Characteristics
✔ Unordered
✔ No duplicates
✔ Mutable
✔ Elements must be immutable (int, str, tuple)
🔹 Accessing Elements
Sets do NOT support indexing.
s = {1, 2, 3}
# s[0] ❌ Error
To access elements:
for item in s:
print(item)
📌 Important Set Methods
1️⃣ add()
Add single element.
s = {1, 2}
s.add(3)
print(s)
2️⃣ update()
Add multiple elements.
s = {1, 2}
s.update([3, 4, 5])
print(s)
3️⃣ remove()
Removes element (Error if not found).
s = {1, 2, 3}
s.remove(2)
4️⃣ discard()
Removes element (No error if not found).
s = {1, 2, 3}
s.discard(5) # No error
5️⃣ pop()
Removes random element (because unordered).
s = {10, 20, 30}
s.pop()
print(s)
6️⃣ clear()
Remove all elements.
s = {1, 2, 3}
s.clear()
print(s)
7️⃣ copy()
Create shallow copy.
s1 = {1, 2, 3}
s2 = s1.copy()
🔥 Set Operations (Very Important)
Sets are powerful for mathematical operations.
1️⃣ Union
Combines two sets.
a = {1, 2, 3}
b = {3, 4, 5}
print(a.union(b))
Or:
print(a | b)
Output:
{1, 2, 3, 4, 5}
2️⃣ Intersection
Common elements.
print(a.intersection(b))
Or:
print(a & b)
Output:
{3}
3️⃣ Difference
Elements in A but not in B.
print(a.difference(b))
Or:
print(a - b)
4️⃣ Symmetric Difference
Elements not common in both.
print(a.symmetric_difference(b))
Or:
print(a ^ b)
🔥 Subset and Superset
issubset()
a = {1, 2}
b = {1, 2, 3}
print(a.issubset(b))
a = {1, 2}
b = {1, 2, 3}
print(a.issubset(b))
issuperset()
print(b.issuperset(a))
print(b.issuperset(a))
🔥 Frozen Set (Immutable Set)
fs = frozenset([1, 2, 3])
fs = frozenset([1, 2, 3])
Cannot modify.
Used when:
Want immutable set
Use as dictionary key
🔥 Practical Examples
Remove Duplicates from List
numbers = [1, 2, 2, 3, 4, 4]
unique = set(numbers)
print(unique)
numbers = [1, 2, 2, 3, 4, 4]
unique = set(numbers)
print(unique)
Find Common Elements Between Lists
a = [1, 2, 3]
b = [2, 3, 4]
common = set(a) & set(b)
print(common)
a = [1, 2, 3]
b = [2, 3, 4]
common = set(a) & set(b)
print(common)
🔥 Set Comprehension
squares = {x*x for x in range(5)}
print(squares)
squares = {x*x for x in range(5)}
print(squares)
🔥 Membership Testing (Very Fast)
s = {1, 2, 3}
if 2 in s:
print("Found")
s = {1, 2, 3}
if 2 in s:
print("Found")
Set lookup is O(1) average time complexity.
📌 Summary of Important Set Methods
| Method | Purpose |
|---|---|
| add() | Add element |
| update() | Add multiple |
| remove() | Remove (error if missing) |
| discard() | Remove (no error) |
| pop() | Remove random |
| clear() | Remove all |
| union() | Combine sets |
| intersection() | Common elements |
| difference() | Subtract sets |
| symmetric_difference() | Non-common elements |
| issubset() | Check subset |
| issuperset() | Check superset |
| copy() | Copy set |
🔥 Set vs List vs Tuple
| Feature | Set | List | Tuple |
|---|---|---|---|
| Ordered | ❌ No | ✔ Yes | ✔ Yes |
| Duplicates | ❌ No | ✔ Yes | ✔ Yes |
| Mutable | ✔ Yes | ✔ Yes | ❌ No |
| Indexing | ❌ No | ✔ Yes | ✔ Yes |
🐍 Section 4: Functions in Python
🔹 What is a Function?
A function is a reusable block of code that performs a specific task.
Why use functions?
✔ Avoid repetition
✔ Make code modular
✔ Improve readability
✔ Easy testing
1️⃣ Defining a Function
🔹 Basic Syntax
def function_name(parameters):
# code block
return value
def function_name(parameters):
# code block
return value
🔹 Simple Example
def greet():
print("Hello, Hari!")
greet()
def greet():
print("Hello, Hari!")
greet()
Output:
Hello, Hari!
🔹 Function with Parameters
def greet(name):
print(f"Hello, {name}!")
greet("Hari")
def greet(name):
print(f"Hello, {name}!")
greet("Hari")
🔹 Function with Return Value
def add(a, b):
return a + b
result = add(10, 20)
print(result)
def add(a, b):
return a + b
result = add(10, 20)
print(result)
2️⃣ Default Parameters
Allows parameters to have default values.
🔹 Example
def greet(name="Guest"):
print(f"Hello, {name}!")
greet() # Uses default
greet("Hari") # Overrides default
def greet(name="Guest"):
print(f"Hello, {name}!")
greet() # Uses default
greet("Hari") # Overrides default
⚠️ Rule: Default parameters must come after non-default parameters.
❌ Wrong:
def test(a=5, b):
pass
✔ Correct:
def test(a, b=5):
pass
3️⃣ Keyword Arguments
Instead of passing arguments by position, pass by name.
🔹 Positional Arguments
def student(name, age):
print(name, age)
student("Hari", 25)
def student(name, age):
print(name, age)
student("Hari", 25)
🔹 Keyword Arguments
student(age=25, name="Hari")
student(age=25, name="Hari")
Order does not matter.
🔹 Mixing Positional + Keyword
student("Hari", age=25)
student("Hari", age=25)
But positional must come first.
4️⃣ Recursive Functions
A function that calls itself.
🔹 Example: Factorial
Mathematical:
5! = 5 × 4 × 3 × 2 × 1
Recursive Implementation
def factorial(n):
if n == 1:
return 1
return n * factorial(n - 1)
print(factorial(5))
def factorial(n):
if n == 1:
return 1
return n * factorial(n - 1)
print(factorial(5))
🔹 Important Concepts in Recursion
✔ Base case (Stopping condition)
✔ Recursive case (Function calls itself)
Without base case → Infinite recursion.
🔹 Example: Fibonacci
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(6))
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(6))
5️⃣ Lambda Expressions (Anonymous Functions)
Used to create small functions in one line.
🔹 Syntax
lambda parameters: expression
lambda parameters: expression
🔹 Example
Normal function:
def square(x):
return x * x
Lambda version:
square = lambda x: x * x
print(square(5))
🔹 Lambda with Multiple Parameters
add = lambda a, b: a + b
print(add(10, 20))
add = lambda a, b: a + b
print(add(10, 20))
🔹 Lambda with sorted()
students = [("Hari", 25), ("Mohan", 22)]
students.sort(key=lambda x: x[1])
print(students)
students = [("Hari", 25), ("Mohan", 22)]
students.sort(key=lambda x: x[1])
print(students)
6️⃣ Docstrings
Used to document functions.
🔹 Basic Docstring
def add(a, b):
"""
This function returns the sum of two numbers.
"""
return a + b
def add(a, b):
"""
This function returns the sum of two numbers.
"""
return a + b
🔹 Access Docstring
print(add.__doc__)
print(add.__doc__)
🔹 Best Practice Docstring Format
def multiply(a, b):
"""
Multiply two numbers.
Parameters:
a (int): First number
b (int): Second number
Returns:
int: Product of a and b
"""
return a * b
def multiply(a, b):
"""
Multiply two numbers.
Parameters:
a (int): First number
b (int): Second number
Returns:
int: Product of a and b
"""
return a * b
🔥 Advanced Concepts (Interview Important)
🔹 *args (Variable Arguments)
def add(*numbers):
return sum(numbers)
print(add(1, 2, 3, 4))
def add(*numbers):
return sum(numbers)
print(add(1, 2, 3, 4))
🔹 **kwargs (Keyword Arguments)
def student(**details):
print(details)
student(name="Hari", age=25)
def student(**details):
print(details)
student(name="Hari", age=25)
🔹 Return Multiple Values
def calculate(a, b):
return a + b, a - b
sum_val, diff_val = calculate(10, 5)
print(sum_val, diff_val)
def calculate(a, b):
return a + b, a - b
sum_val, diff_val = calculate(10, 5)
print(sum_val, diff_val)
Python returns tuple internally.
🔥 Function Scope
Local vs Global
x = 10
def test():
x = 5
print(x)
test()
print(x)
x = 10
def test():
x = 5
print(x)
test()
print(x)
📌 Summary
| Concept | Purpose |
|---|---|
| def | Define function |
| return | Send value back |
| Default parameter | Predefined value |
| Keyword arguments | Named arguments |
| Recursion | Function calls itself |
| Lambda | One-line anonymous function |
| Docstring | Function documentation |
| *args | Variable positional arguments |
| **kwargs | Variable keyword arguments |
🐍 Section 8: Exception Handling in Python
🔹 What is an Exception?
An exception is an error that occurs during program execution.
Example:
print(10 / 0)
Output:
ZeroDivisionError: division by zero
Without handling → program crashes ❌
With handling → program continues gracefully ✔
🔥 Why Exception Handling is Important?
✔ Prevent program crash
✔ Show user-friendly message
✔ Control program flow
✔ Handle unexpected inputs
1️⃣ try…except
Used to handle errors gracefully.
🔹 Basic Syntax
try:
# risky code
except:
# error handling code
🔹 Example
try:
num = int(input("Enter a number: "))
print(10 / num)
except:
print("Invalid input or division by zero!")
Now program doesn’t crash.
🔹 Handling Specific Exceptions (Best Practice)
try:
num = int(input("Enter a number: "))
print(10 / num)
except ZeroDivisionError:
print("Cannot divide by zero!")
except ValueError:
print("Please enter a valid number!")
✔ Always catch specific exceptions.
🔹 Multiple Exceptions in One Line
try:
x = int("abc")
except (ValueError, TypeError):
print("Error occurred")
🔹 Exception Object
try:
x = 10 / 0
except ZeroDivisionError as e:
print("Error:", e)
2️⃣ try…except…finally
finally block runs no matter what happens.
🔹 Syntax
try:
# risky code
except:
# error handling
finally:
# always executes
🔹 Example
try:
file = open("test.txt")
print(file.read())
except FileNotFoundError:
print("File not found")
finally:
print("Execution completed")
Even if error happens → finally runs.
🔹 Real-world Example (Important)
try:
file = open("data.txt", "r")
data = file.read()
except FileNotFoundError:
print("File missing")
finally:
print("Closing program")
Usually used for:
Closing files
Releasing resources
Database connections
3️⃣ try…except…else
else runs only if NO exception occurs.
🔹 Syntax
try:
# risky code
except:
# error handling
else:
# runs if no error
🔹 Example
try:
num = int(input("Enter number: "))
except ValueError:
print("Invalid input")
else:
print("You entered:", num)
If input is valid → else runs
If error → except runs
🔥 Complete Structure (All Together)
try:
num = int(input("Enter number: "))
result = 10 / num
except ZeroDivisionError:
print("Cannot divide by zero")
except ValueError:
print("Invalid input")
else:
print("Result:", result)
finally:
print("Done")
🔥 Execution Flow
tryblock runs firstIf error → matching
exceptrunsIf no error →
elserunsfinallyalways runs
🔥 Raising Exceptions Manually
You can create custom errors using raise.
age = -5
if age < 0:
raise ValueError("Age cannot be negative")
🔥 Custom Exception
class MyError(Exception):
pass
try:
raise MyError("Custom error occurred")
except MyError as e:
print(e)
🔥 Common Built-in Exceptions
| Exception | Cause |
|---|---|
| ZeroDivisionError | Division by zero |
| ValueError | Wrong value type |
| TypeError | Wrong type operation |
| IndexError | Invalid index |
| KeyError | Missing dictionary key |
| FileNotFoundError | File not found |
🔥 Practical Example
Safe dictionary access:
data = {"name": "Hari"}
try:
print(data["age"])
except KeyError:
print("Key not found")
🔥 Interview-Level Concept
Why use else?
Cleaner structure:
try:
value = int("10")
except ValueError:
print("Error")
else:
print(value * 2)
Avoids placing normal logic inside try.
📌 Summary
| Block | When It Runs |
|---|---|
| try | Always first |
| except | If exception occurs |
| else | If no exception |
| finally | Always runs |
Working with Files in Python
Python provides built-in functions and modules to work with files.
🔹 Opening a File
Basic syntax:
file = open("filename.txt", "mode")
Better way (recommended):
with open("filename.txt", "mode") as file:
# work with file
✔ with automatically closes file
✔ Prevents memory leaks
📌 File Modes
| Mode | Description |
|---|---|
"r" | Read (default) |
"w" | Write (overwrites file) |
"a" | Append |
"x" | Create new file |
"rb" | Read binary |
"wb" | Write binary |
1️⃣ Read from a Text File
🔹 Read Entire File
with open("sample.txt", "r") as file:
content = file.read()
print(content)
with open("sample.txt", "r") as file:
content = file.read()
print(content)
🔹 Read Line by Line
with open("sample.txt", "r") as file:
for line in file:
print(line.strip())
with open("sample.txt", "r") as file:
for line in file:
print(line.strip())
🔹 Read One Line
with open("sample.txt", "r") as file:
print(file.readline())
with open("sample.txt", "r") as file:
print(file.readline())
🔹 Read All Lines as List
with open("sample.txt", "r") as file:
lines = file.readlines()
print(lines)
with open("sample.txt", "r") as file:
lines = file.readlines()
print(lines)
2️⃣ Write to a Text File
⚠️ "w" overwrites file if it exists.
with open("sample.txt", "w") as file:
file.write("Hello, Hari!\n")
file.write("Welcome to Python.")
3️⃣ Append to a File
with open("sample.txt", "a") as file:
file.write("\nNew line added.")
with open("sample.txt", "a") as file:
file.write("\nNew line added.")
4️⃣ Create a New Text File
Using "x" mode:
with open("newfile.txt", "x") as file:
file.write("This is a new file.")
⚠️ If file exists → error
5️⃣ Check if a File Exists
Using os module:
import os
if os.path.exists("sample.txt"):
print("File exists")
else:
print("File does not exist")
6️⃣ Read CSV Files
Python provides built-in csv module.
🔹 Example CSV File (data.csv)
name,age,city
Hari,25,Bangalore
Mohan,22,Delhi
name,age,city
Hari,25,Bangalore
Mohan,22,Delhi
🔹 Read CSV File
import csv
with open("data.csv", "r") as file:
reader = csv.reader(file)
for row in reader:
print(row)
import csv
with open("data.csv", "r") as file:
reader = csv.reader(file)
for row in reader:
print(row)
Output:
['name', 'age', 'city']
['Hari', '25', 'Bangalore']
['Mohan', '22', 'Delhi']
🔹 Read CSV as Dictionary
import csv
with open("data.csv", "r") as file:
reader = csv.DictReader(file)
for row in reader:
print(row["name"], row["age"])
import csv
with open("data.csv", "r") as file:
reader = csv.DictReader(file)
for row in reader:
print(row["name"], row["age"])
7️⃣ Write CSV Files
🔹 Writing Basic CSV
import csv
data = [
["name", "age", "city"],
["Hari", 25, "Bangalore"],
["Mohan", 22, "Delhi"]
]
with open("output.csv", "w", newline="") as file:
writer = csv.writer(file)
writer.writerows(data)
import csv
data = [
["name", "age", "city"],
["Hari", 25, "Bangalore"],
["Mohan", 22, "Delhi"]
]
with open("output.csv", "w", newline="") as file:
writer = csv.writer(file)
writer.writerows(data)
🔹 Writing CSV with Dictionary
import csv
data = [
{"name": "Hari", "age": 25},
{"name": "Mohan", "age": 22}
]
with open("output.csv", "w", newline="") as file:
fieldnames = ["name", "age"]
writer = csv.DictWriter(file, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(data)
import csv
data = [
{"name": "Hari", "age": 25},
{"name": "Mohan", "age": 22}
]
with open("output.csv", "w", newline="") as file:
fieldnames = ["name", "age"]
writer = csv.DictWriter(file, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(data)
8️⃣ Rename a File
Using os.rename():
import os
os.rename("oldname.txt", "newname.txt")
9️⃣ Delete a File
Using os.remove():
import os
os.remove("sample.txt")
🔥 Handling File Exceptions (Important)
import os
try:
with open("sample.txt", "r") as file:
print(file.read())
except FileNotFoundError:
print("File not found")
import os
try:
with open("sample.txt", "r") as file:
print(file.read())
except FileNotFoundError:
print("File not found")
🔥 Real-World Example
Append user input to file:
name = input("Enter your name: ")
with open("users.txt", "a") as file:
file.write(name + "\n")
🔥 Best Practices
✔ Always use with statement
✔ Handle exceptions
✔ Close files properly
✔ Use newline="" when writing CSV
✔ Validate file existence
📌 Summary
| Operation | Method |
|---|---|
| Read file | open(..., "r") |
| Write file | open(..., "w") |
| Append file | open(..., "a") |
| Create file | open(..., "x") |
| Check exists | os.path.exists() |
| Read CSV | csv.reader() |
| Write CSV | csv.writer() |
| Rename file | os.rename() |
| Delete file | os.remove() |
import collections
print(dir(collections))
…and grabbed a subset. Let’s go through everything in that list, but in a sane way:
First: things you actually use (public API)
Then: internal / helper stuff (you normally ignore)
✅ Public, Useful Things
1. ChainMap
What it is: A view over multiple dicts as if they were one.
Lookup: checks first dict, then second, etc.
Useful for: layered configs, scopes, overriding defaults.
from collections import ChainMap
defaults = {"timeout": 30, "retries": 3}
env = {"timeout": 10}
config = ChainMap(env, defaults)
print(config["timeout"]) # 10 (from env)
print(config["retries"]) # 3 (from defaults)
2. Counter
What it is: A dict subclass for counting hashable items.
Key = item, Value = count.
Great for frequency problems (DSA, interviews).
from collections import Counter
c = Counter("banana")
print(c) # Counter({'a': 3, 'n': 2, 'b': 1})
print(c["a"]) # 3
print(c.most_common(1)) # [('a', 3)]
3. OrderedDict
What it is: A dict that remembers insertion order.
Before Python 3.7, normal
dictdidn’t guarantee order.Still useful for some advanced patterns (like LRU Cache).
from collections import OrderedDict
od = OrderedDict()
od["a"] = 1
od["b"] = 2
print(od) # OrderedDict([('a', 1), ('b', 2)])
4. UserDict
What it is: A wrapper around dict for easy subclassing.
Instead of subclassing dict directly, you subclass
UserDict.Safer / more predictable inheritance.
from collections import UserDict
class MyDict(UserDict):
def __setitem__(self, key, value):
print("Setting:", key, value)
super().__setitem__(key, value)
d = MyDict()
d["x"] = 10
5. UserList
What it is: Same idea as UserDict but for list.
from collections import UserList
class MyList(UserList):
def append(self, item):
print("Appending:", item)
super().append(item)
l = MyList()
l.append(5)
6. UserString
What it is: Wrapper around string for easy subclassing.
from collections import UserString
class MyString(UserString):
def shout(self):
return self.data.upper() + "!!!"
s = MyString("hello")
print(s.shout()) # HELLO!!!
7. defaultdict
What it is: Dict with default value factory.
Avoids
KeyErrorby creating default values.
from collections import defaultdict
d = defaultdict(int)
d["a"] += 1
print(d) # defaultdict(<class 'int'>, {'a': 1})
8. deque
What it is: Double-ended queue.
Fast
append/appendleft/pop/popleft.Used a LOT in DSA (BFS, sliding window).
from collections import deque
dq = deque([1, 2, 3])
dq.appendleft(0)
dq.append(4)
print(dq) # deque([0, 1, 2, 3, 4])
9. namedtuple
What it is: Factory to create tuple subclasses with named fields.
Lightweight “class-like” structure.
from collections import namedtuple
Point = namedtuple("Point", ["x", "y"])
p = Point(2, 3)
print(p.x, p.y) # 2 3
10. abc
What it is: The abc module (abstract base classes) re-exported.
Contains abstract container types (
Mapping,Sequence, etc.).Used for
isinstancechecks and custom container types.
from collections.abc import Mapping, Sequence
⚙️ Internal / Implementation Details (You Normally Don’t Use)
These things exist for the implementation of collections itself, or for internal mechanics. You rarely (almost never) need them directly.
I’ll keep them short:
11. _Link
Internal helper class/structure used by OrderedDict to maintain its doubly-linked list of entries.
12–14. _OrderedDictItemsView, _OrderedDictKeysView, _OrderedDictValuesView
Specialized view classes used when you call:
od.keys()
od.items()
od.values()
on an OrderedDict. They track order + changes efficiently.
15. __all__
List of public names that from collections import * will import.
16. __builtins__
Reference to the built-in namespace (implementation detail).
17. __cached__
Path to the cached compiled file (.pyc), used by Python’s import system.
18. __doc__
Module docstring for collections.
19. __file__
Path to the source file of the collections module on your system.
20. __loader__
Object that loaded the module (part of Python import internals).
21. __name__
The name of the module, "collections".
22. __package__
Package name for relative imports. For collections, usually "collections".
23. __path__
Only relevant when module is a package; for collections, may be used to locate submodules.
24. __spec__
Import specification object that describes how this module was loaded.
25. _chain
Internal helper used by ChainMap or other utilities to chain iterables.
26. _collections_abc
Internal module that actually defines the abstract base classes for containers (Mapping, MutableMapping, etc.), then collections.abc exposes them.
27. _count_elements
Internal helper function used by Counter to efficiently count elements (implemented in C for speed in CPython).
28. _deque_iterator
Internal iterator type used for iterating over deque efficiently.
29. _eq
Internal equality helper used by some of the collections’ classes.
30. _iskeyword
Internal helper checking if a string is a Python keyword (used by namedtuple to avoid illegal field names).
31. _itemgetter
Internal helper related to operator.itemgetter, used in namedtuple or views.
32. _proxy
Internal wrapper / proxy object used by some collections internals (often for type-safe behavior).
33. _recursive_repr
Internal decorator to avoid infinite recursion in __repr__ for self-referential structures.
34. _repeat
Internal helper similar to itertools.repeat, for performance.
35. _starmap
Internal helper similar to itertools.starmap, used in named tuple or other internal operations.
36. _sys
Reference to the sys module used internally in collections.
37. _tuplegetter
Internal helper used by namedtuple to generate efficient getters for tuple fields.
🧠 Big Picture
From your list, the ones you really care about in real code & interviews:
CounterdefaultdictdequenamedtupleOrderedDictChainMapUserDict/UserList/UserString(when subclassing)
Everything starting with _ or __ is mainly internal or metadata.
Perfect 👌
Let’s go deep into OOP (Object-Oriented Programming) in Python — beginner to advanced, with clean explanations and examples.
🐍 OOP in Python (Object-Oriented Programming)
🔹 What is OOP?
OOP is a programming paradigm based on:
Objects
Classes
Encapsulation
Abstraction
Inheritance
Polymorphism
🧱 1️⃣ Class and Object
🔹 Class
A class is a blueprint for creating objects.
class Person:
pass
🔹 Object
An object is an instance of a class.
p = Person()
print(p)
🧠 2️⃣ Constructor (__init__)
Used to initialize object data.
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
p1 = Person("Hari", 25)
print(p1.name)
🔹 What is self?
Refers to current object
Required in instance methods
Automatically passed by Python
🔹 3️⃣ Instance Methods
class Person:
def __init__(self, name):
self.name = name
def greet(self):
print(f"Hello, I am {self.name}")
p = Person("Hari")
p.greet()
🔐 4️⃣ Encapsulation
Hiding internal details.
🔹 Public Variable
self.name
🔹 Protected (Convention)
self._salary
🔹 Private (Name Mangling)
self.__password
Example:
class Bank:
def __init__(self):
self.__balance = 1000
def get_balance(self):
return self.__balance
b = Bank()
print(b.get_balance())
🎭 5️⃣ Inheritance
Allows one class to inherit another.
🔹 Example
class Animal:
def speak(self):
print("Animal speaks")
class Dog(Animal):
def bark(self):
print("Dog barks")
d = Dog()
d.speak()
d.bark()
🔁 6️⃣ Method Overriding
Child class overrides parent method.
class Animal:
def speak(self):
print("Animal sound")
class Dog(Animal):
def speak(self):
print("Bark")
d = Dog()
d.speak()
🎭 7️⃣ Polymorphism
Same method name, different behavior.
class Cat:
def speak(self):
print("Meow")
class Dog:
def speak(self):
print("Bark")
for animal in (Cat(), Dog()):
animal.speak()
🧩 8️⃣ Abstraction
Hide implementation details.
Use abc module.
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self):
pass
class Circle(Shape):
def area(self):
return 3.14 * 5 * 5
🔄 9️⃣ Class Variables vs Instance Variables
class Car:
wheels = 4 # class variable
def __init__(self, brand):
self.brand = brand # instance variable
c1 = Car("BMW")
print(c1.wheels)
🔹 🔟 Static Method
Does not access instance or class.
class Math:
@staticmethod
def add(a, b):
return a + b
print(Math.add(5, 3))
🔹 1️⃣1️⃣ Class Method
Accesses class variable.
class Car:
wheels = 4
@classmethod
def get_wheels(cls):
return cls.wheels
print(Car.get_wheels())
🔁 1️⃣2️⃣ Multiple Inheritance
class A:
pass
class B:
pass
class C(A, B):
pass
🧠 MRO (Method Resolution Order)
Python decides method lookup order using MRO.
print(C.__mro__)
🔥 1️⃣3️⃣ Magic Methods (Dunder Methods)
Special methods starting with __.
Examples:
__init____str____repr____len____add__
Example
class Person:
def __init__(self, name):
self.name = name
def __str__(self):
return f"Person: {self.name}"
p = Person("Hari")
print(p)
📌 OOP Pillars Summary
| Concept | Meaning |
|---|---|
| Encapsulation | Hide data |
| Abstraction | Hide implementation |
| Inheritance | Reuse code |
| Polymorphism | Same interface, different behavior |
🎯 Interview-Important Topics
If preparing seriously:
✔ Encapsulation
✔ Inheritance
✔ Polymorphism
✔ Method overriding
✔ Static vs Class method
✔ MRO
✔ Magic methods
✔ Abstract classes
Perfect 👌
Let’s go deep into Python Concurrency — structured, practical, and interview-ready.
🐍 Python Concurrency
🔹 What is Concurrency?
Concurrency means:
Running multiple tasks in overlapping time.
Example:
Handling multiple API requests
Downloading multiple files
Processing background jobs
🔥 Concurrency vs Parallelism
| Term | Meaning |
|---|---|
| Concurrency | Tasks overlap in execution |
| Parallelism | Tasks run at the same time (multiple CPU cores) |
🧠 Why Concurrency in Python is Special?
Because of:
🚫 GIL (Global Interpreter Lock)
Only one thread executes Python bytecode at a time
Affects CPU-bound tasks
Does NOT block I/O-bound concurrency
Only one thread executes Python bytecode at a time
Affects CPU-bound tasks
Does NOT block I/O-bound concurrency
🎯 Types of Concurrency in Python
Threading (I/O-bound tasks)
Multiprocessing (CPU-bound tasks)
Asyncio (Async/Await) (High-performance I/O)
Threading (I/O-bound tasks)
Multiprocessing (CPU-bound tasks)
Asyncio (Async/Await) (High-performance I/O)
1️⃣ Threading
Best for:
API calls
File I/O
Network requests
🔹 Basic Example
import threading
import time
def task():
print("Task started")
time.sleep(2)
print("Task completed")
t1 = threading.Thread(target=task)
t2 = threading.Thread(target=task)
t1.start()
t2.start()
t1.join()
t2.join()
import threading
import time
def task():
print("Task started")
time.sleep(2)
print("Task completed")
t1 = threading.Thread(target=task)
t2 = threading.Thread(target=task)
t1.start()
t2.start()
t1.join()
t2.join()
🔹 When to Use Threading
✔ I/O-bound tasks
✔ Waiting for network response
✔ Multiple small tasks
❌ Not good for CPU-heavy computation (due to GIL)
2️⃣ Multiprocessing
Best for:
CPU-intensive tasks
ML training
Heavy computation
Each process:
Has its own memory
Has its own Python interpreter
No GIL blocking
🔹 Example
from multiprocessing import Process
import time
def task():
print("Processing...")
time.sleep(2)
p1 = Process(target=task)
p2 = Process(target=task)
p1.start()
p2.start()
p1.join()
p2.join()
from multiprocessing import Process
import time
def task():
print("Processing...")
time.sleep(2)
p1 = Process(target=task)
p2 = Process(target=task)
p1.start()
p2.start()
p1.join()
p2.join()
🔹 When to Use Multiprocessing
✔ CPU-bound workloads
✔ Data processing
✔ Parallel model inference
3️⃣ Asyncio (Modern Approach)
Best for:
High-performance web servers
APIs
Chat systems
Real-time apps
🔹 Example
import asyncio
async def task():
print("Start")
await asyncio.sleep(2)
print("End")
async def main():
await asyncio.gather(task(), task())
asyncio.run(main())
import asyncio
async def task():
print("Start")
await asyncio.sleep(2)
print("End")
async def main():
await asyncio.gather(task(), task())
asyncio.run(main())
🔹 Why Async is Powerful?
Single-threaded
Event loop-based
Non-blocking I/O
Highly scalable
Single-threaded
Event loop-based
Non-blocking I/O
Highly scalable
Used in:
FastAPI
Async web scraping
High-concurrency servers
🔥 Thread vs Process vs Async
| Feature | Threading | Multiprocessing | Asyncio |
|---|---|---|---|
| GIL affected | Yes | No | Yes (but non-blocking) |
| Best for | I/O | CPU | High I/O |
| Memory | Shared | Separate | Shared |
| Speed | Medium | High (CPU) | High (I/O) |
🧠 Real-world Example
Web Server (FastAPI)
FastAPI uses:
Async functions
Event loop
Non-blocking requests
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def home():
return {"message": "Hello"}
🔥 ThreadPoolExecutor
Easier way to manage threads:
from concurrent.futures import ThreadPoolExecutor
def square(x):
return x * x
with ThreadPoolExecutor() as executor:
results = executor.map(square, [1, 2, 3, 4])
print(list(results))
🔥 ProcessPoolExecutor
from concurrent.futures import ProcessPoolExecutor
with ProcessPoolExecutor() as executor:
results = executor.map(square, [1, 2, 3, 4])
print(list(results))
from concurrent.futures import ProcessPoolExecutor
with ProcessPoolExecutor() as executor:
results = executor.map(square, [1, 2, 3, 4])
print(list(results))
⚠️ Common Concurrency Problems
Race condition
Deadlock
Shared state mutation
Blocking calls inside async
Race condition
Deadlock
Shared state mutation
Blocking calls inside async
🔐 Thread Safety (Lock Example)
import threading
lock = threading.Lock()
def safe_task():
with lock:
print("Safe access")
import threading
lock = threading.Lock()
def safe_task():
with lock:
print("Safe access")
🧠 Interview-Level Points
If preparing seriously:
✔ Understand GIL clearly
✔ Know when to use threads vs processes
✔ Understand async event loop
✔ Know I/O vs CPU-bound difference
✔ Thread safety basics
✔ Deadlock explanation
🚀 When to Use What (Practical Guide)
🧮 CPU Heavy Task?
→ Use multiprocessing
🌐 API Calls / DB Queries?
→ Use async
🗂 File Handling?
→ Threading or async
🔥 Example: High-Performance LLM API
If building LLM backend:
Async FastAPI
Redis caching
Background tasks
Multiprocessing for embedding
Streaming responses
🎯 Summary
Python concurrency options:
Threading → I/O tasks
Multiprocessing → CPU tasks
Asyncio → Scalable I/O
🧩 Advanced Python: Imports & Modules
Python’s import system is the backbone of how you organize and reuse code.
Understanding it deeply makes you way stronger as a Python dev.
1. What is a Module?
A module is just a .py file that contains Python code (functions, classes, variables).
Example:
math_utils.py:
# math_utils.py
PI = 3.14159
def add(a, b):
return a + b
def area_of_circle(r):
return PI * r * r
Using this module:
# main.py
import math_utils
print(math_utils.PI)
print(math_utils.add(2, 3))
print(math_utils.area_of_circle(5))
Key idea:
import math_utilsgives you the module object, and you access its contents viamath_utils.something.
2. Different Ways to Import
2.1 import module
import math
print(math.sqrt(16))
import math
print(math.sqrt(16))
✅ Clear
✅ Namespaced
❌ Slightly more typing
2.2 import module as alias
import numpy as np
import math_utils as mu
print(mu.add(1, 2))
import numpy as np
import math_utils as mu
print(mu.add(1, 2))
Good when:
Module name is long
You want conventional alias (
np,pd,plt)
2.3 from module import name
from math_utils import add, PI
print(add(2, 3))
print(PI)
from math_utils import add, PI
print(add(2, 3))
print(PI)
✅ Less typing
⚠️ But it can pollute the namespace if you import too many names.
2.4 from module import * (Wildcard)
from math_utils import *
print(add(2, 3))
from math_utils import *
print(add(2, 3))
⚠️ Not recommended in real projects because:
It hides where things come from
Can overwrite names silently
Makes code harder to debug
Use only in:
Quick REPL / experiments
Some educational/demo situations
3. Packages and __init__.py
A package is a folder with an __init__.py file.
Example project:
my_project/
main.py
utils/
__init__.py
math_utils.py
string_utils.py
math_utils.py:
def add(a, b):
return a + b
string_utils.py:
def shout(text):
return text.upper() + "!"
utils/__init__.py:
from .math_utils import add
from .string_utils import shout
__all__ = ["add", "shout"]
Now in main.py:
from utils import add, shout
print(add(2, 3))
print(shout("hello"))
Here:
utilsis a package__init__.pycontrols whatfrom utils import ...exposes
4. Absolute vs Relative Imports
4.1 Absolute Import
From project root:
from utils.math_utils import add
This is unambiguous and recommended for bigger projects.
4.2 Relative Import (inside a package)
Inside utils/string_utils.py:
from .math_utils import add # from same package
from ..config import settings # from parent package (if exists)
.→ same directory..→ parent directory
Relative imports only work inside packages, not from top-level scripts run directly.
5. if __name__ == "__main__":
Every module has a built-in variable __name__.
If you import the module →
__name__ == "module_name"If you run the module directly →
__name__ == "__main__"
Pattern:
# math_utils.py
def add(a, b):
return a + b
if __name__ == "__main__":
# this runs only when we execute: python math_utils.py
print(add(2, 3))
This is great for:
Quick tests
Demo code
CLI entry points
6. How Import Actually Works (Mental Model)
When you do:
import math_utils
Python roughly does:
Look for
math_utilsin sys.modules (cache)If not found:
Search in directories listed in
sys.pathLoad and execute
math_utils.pyStore the module object in
sys.modules["math_utils"]
Bind the name
math_utilsin your current file to that module object.
So imports are cached — second import is basically free.
You can inspect:
import sys, math_utils
print(sys.modules.keys()) # all loaded modules
print(math_utils.__file__) # file path
print(dir(math_utils)) # module attributes
7. Circular Imports (Common Pitfall)
Two modules import each other:
a.py
b.py
a.py:
from b import func_b
def func_a():
func_b()
b.py:
from a import func_a
def func_b():
func_a()
This can lead to:
ImportErrorAttributeError (module loaded but object not defined yet)
Fix strategies:
Move shared code into a third module
Use local imports (import inside function) to delay import
Redesign modules to be less tightly coupled
Example of local import:
# b.py
def func_b():
from a import func_a
func_a()
8. Realistic Example: Project Layout with Imports
my_app/
main.py
app/
__init__.py
models.py
services.py
config.py
my_app/
main.py
app/
__init__.py
models.py
services.py
config.py
app/config.py:
DB_URL = "postgresql://..."
app/models.py:
from .config import DB_URL
class User:
def __init__(self, name):
self.name = name
app/services.py:
from .models import User
def create_user(name: str):
return User(name)
main.py:
from app.services import create_user
if __name__ == "__main__":
user = create_user("Hari")
print(user.name)
This is close to how real apps are structured.
9. Import Best Practices (for your “Advanced Python” course)
✅ Prefer absolute imports in larger projects
✅ Use from module import name for a few specific functions, not everything
❌ Avoid from module import * in production
✅ Keep import section grouped and ordered:
Standard library
Third-party
Local imports
✅ Prefer absolute imports in larger projects
✅ Use from module import name for a few specific functions, not everything
❌ Avoid from module import * in production
✅ Keep import section grouped and ordered:
Standard library
Third-party
Local imports
Example style:
# standard lib
import os
import sys
from pathlib import Path
# third-party
import requests
from pydantic import BaseModel
# local
from app.services import create_user
10. Tiny Practice Snippet (Good for your tutorial)
Task:
Create a small package and import from it.
playground/
main.py
utils/
__init__.py
math_utils.py
utils/math_utils.py:
PI = 3.14159
def circle_area(r: float) -> float:
return PI * r * r
utils/__init__.py:
from .math_utils import circle_area, PI
__all__ = ["circle_area", "PI"]
main.py:
from utils import circle_area, PI
if __name__ == "__main__":
print("PI:", PI)
print("Area of radius 5:", circle_area(5))
Run:
python main.py
Comments
Post a Comment