
Python Revision Notes - Comprehensive Study Guide
Section 1: Python Environment Setup
4. Different Ways of Creating Python Environment
[image:1]
Python environments help isolate dependencies and prevent conflicts between different projects.
Virtual Environment (venv)^1
- Purpose: Create isolated Python environments
- Creation:
python -m venv myenv - Activation:
- Windows:
myenv\Scripts\activate - Linux/Mac:
source myenv/bin/activate - Deactivation:
deactivate - Usage: Best for pure Python projects
- Example:
# Create environment
python -m venv project_env
# Activate (Windows)
project_env\Scripts\activate
# Install packages
pip install requests numpy
# Deactivate
deactivate
Conda Environment^2
- Purpose: Package and environment management for multiple languages
- Creation:
conda create --name myenv python=3.9 - Activation:
conda activate myenv - Package installation:
conda install numpy - Deactivation:
conda deactivate - Usage: Best for data science projects
- Example:
# Create environment with specific Python version
conda create --name data_science python=3.9
# Activate environment
conda activate data_science
# Install packages
conda install numpy pandas matplotlib
# List environments
conda env list
Pipenv^4
- Purpose: Combines pip and virtualenv functionality
- Creation:
pipenv install(creates Pipfile) - Activation:
pipenv shell - Package installation:
pipenv install package_name - Usage: Modern dependency management
- Example:
# Initialize project
pipenv install
# Install package
pipenv install requests
# Enter shell
pipenv shell
# Install from Pipfile
pipenv install --dev
5. Solve-Conda Not Recognized Issue
Common Solutions:
- Add to PATH: Add Anaconda/Miniconda to system PATH variable^5
- Reinstall: Download from official Anaconda website
- Use Anaconda Prompt: Launch from Start menu instead of regular command prompt
- Manual PATH setup:
- Windows: Add
C:\Users\username\Anaconda3\Scriptsto PATH - Check installation:
conda --version
Section 2: Python Basics
6. Python Basics - Syntax and Semantics
[image:1]
Python Syntax^6
- Definition: Set of rules dictating how code is written
- Key Features:
- Uses English keywords and punctuation
- Indentation-based structure
- Case-sensitive language
- No semicolons required
Python Semantics^6
- Definition: Defines how code is executed and behavior of constructs
- Includes: Variable scope, function calls, object references, data type behavior
Error Types^6:
- Syntax Error: Code doesn't follow language rules
- Example:
print("Hello"(missing closing parenthesis) - Runtime Error: Program runs but encounters execution problems
- Example: Division by zero
- Logic Error: Code runs but produces incorrect results
- Example: Using
+instead of*in calculations
Example:
# Correct syntax and semantics
name = "Python" # Variable assignment
print(f"Hello {name}!") # String formatting
# Case sensitivity demonstration
Name = "Java" # Different variable
print(name) # Outputs: Python
print(Name) # Outputs: Java
7. Variables in Python
Variable Definition^7:
- Concept: Containers to hold information
- Assignment: Use
=operator - Naming Convention: snake_case (lowercase with underscores)
Examples:
# Basic variable assignment
my_name = "Paige" # String
age = 25 # Integer
height = 5.8 # Float
is_student = True # Boolean
# Multiple assignment
x, y, z = 1, 2, 3
# Same value to multiple variables
a = b = c = 10
# Variable reassignment
score = 85
score = score + 5 # Now 90
8. Basic DataTypes in Python
Primary Data Types^7:
Integer (int)
- Description: Whole numbers
- Example:
age = 25 - Operations: Arithmetic operations
Float
- Description: Decimal numbers
- Example:
price = 19.99 - Operations: Mathematical calculations
String (str)
- Description: Text data wrapped in quotes
- Example:
message = "Hello World" - Operations: Concatenation, slicing, formatting
Boolean (bool)
- Description: True or False values
- Example:
is_active = True - Operations: Logical operations
Examples:
# Integer operations
num1 = 10
num2 = 3
print(num1 + num2) # 13
print(num1 // num2) # 3 (floor division)
# String operations
first_name = "John"
last_name = "Doe"
full_name = first_name + " " + last_name
print(len(full_name)) # 8
# Boolean operations
is_valid = True
is_expired = False
result = is_valid and not is_expired # True
# Type checking
print(type(25)) # <class 'int'>
print(type(3.14)) # <class 'float'>
9. Operators in Python
[image:1]
Arithmetic Operators^8:
+Addition:5 + 3 = 8-Subtraction:7 - 2 = 5*Multiplication:4 * 6 = 24/Division:10 / 2 = 5.0//Floor Division:5 // 3 = 1%Modulus:10 % 3 = 1**Exponentiation:5 ** 3 = 125
Comparison Operators^8:
==Equal to:5 == 3→ False!=Not equal:5 != 3→ True>Greater than:5 > 3→ True<Less than:5 < 3→ False>=Greater than or equal:5 >= 3→ True<=Less than or equal:5 <= 3→ False
Logical Operators^8:
andBoth conditions true:(5 > 3) and (3 > 1)→ TrueorEither condition true:(5 > 3) or (3 < 1)→ TruenotInverts result:not (5 > 3)→ False
Assignment Operators^8:
=Assign:x = 5+=Add and assign:x += 1(equivalent tox = x + 1)-=Subtract and assign:x -= 2*=Multiply and assign:x *= 4/=Divide and assign:x /= 2
Examples:
# Arithmetic operations
x = 10
y = 3
print(f"Addition: {x + y}") # 13
print(f"Modulus: {x % y}") # 1
print(f"Power: {x ** y}") # 1000
# Comparison in conditional
age = 18
if age >= 18:
print("Adult")
else:
print("Minor")
# Logical operators
temperature = 25
humidity = 60
if temperature > 20 and humidity < 70:
print("Good weather conditions")
# Assignment operators
counter = 0
counter += 5 # counter is now 5
counter *= 2 # counter is now 10
Section 3: Python Control Flow
10. Conditional Statements (if, elif, else)
[image:2]
Basic if Statement^9:
- Syntax: Tests a condition and executes code if true
- Structure:
if condition: - Indentation: Required for code blocks
if-elif-else Chain^9:
- elif: Short for "else if", tests additional conditions
- else: Executes when no previous conditions are true
- Multiple conditions: Can have multiple elif statements
Examples:
# Simple if statement
score = 85
if score >= 80:
print("Excellent grade!")
# if-elif-else chain
grade = 87
if grade >= 90:
letter = "A"
elif grade >= 80:
letter = "B"
elif grade >= 70:
letter = "C"
elif grade >= 60:
letter = "D"
else:
letter = "F"
print(f"Your grade is: {letter}")
# Nested conditions
age = 20
has_license = True
if age >= 18:
if has_license:
print("Can drive legally")
else:
print("Need to get a license")
else:
print("Too young to drive")
# Multiple conditions
temperature = 22
weather = "sunny"
if temperature > 20 and weather == "sunny":
print("Perfect day for outdoor activities!")
11. Loops in Python
For Loops^11:
- Purpose: Iterate over sequences (lists, strings, ranges)
- Syntax:
for item in sequence: - Usage: When you know the number of iterations
While Loops^12:
- Purpose: Continue execution while condition is true
- Syntax:
while condition: - Usage: When iterations depend on a condition
- Warning: Must update condition to avoid infinite loops
Loop Control Statements:
- break: Exit loop immediately
- continue: Skip current iteration, continue with next
- else: Execute when loop completes normally (not broken)
Examples:
# For loop with range
for i in range(5):
print(f"Count: {i}") # 0, 1, 2, 3, 4
# For loop with list
fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
print(f"I like {fruit}")
# For loop with string
word = "Python"
for letter in word:
print(letter.upper())
# While loop
count = 0
while count < 5:
print(f"Count is: {count}")
count += 1 # Important: update condition variable
# Loop with break and continue
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
for num in numbers:
if num == 3:
continue # Skip 3
if num == 8:
break # Stop at 8
print(num) # Prints: 1, 2, 4, 5, 6, 7
# While loop with else
i = 1
while i <= 3:
print(i)
i += 1
else:
print("Loop completed normally")
# Nested loops
for i in range(3):
for j in range(2):
print(f"i={i}, j={j}")
Section 4: Data Structures Using Python
12. Lists and List Comprehension in Python
[image:2]
Lists^13:
- Definition: Ordered, mutable sequences for storing collections
- Creation: Square brackets
[] - Features: Can store different data types, indexable, dynamic size
List Operations:
# Creating lists
fruits = ["apple", "banana", "cherry"]
numbers = [1, 2, 3, 4, 5]
mixed = [1, "hello", 3.14, True]
# Accessing elements
print(fruits[^0]) # "apple" (first element)
print(fruits[-1]) # "cherry" (last element)
# Modifying lists
fruits.append("date") # Add to end
fruits.insert(1, "blueberry") # Insert at index 1
fruits.remove("banana") # Remove specific item
popped = fruits.pop() # Remove and return last item
# List methods
numbers.extend([6, 7, 8]) # Add multiple items
numbers.sort() # Sort in place
numbers.reverse() # Reverse order
print(len(numbers)) # Get length
# Slicing
print(numbers[1:4]) # Elements from index 1 to 3
print(numbers[:3]) # First 3 elements
print(numbers[2:]) # From index 2 to end
List Comprehension^14:
- Definition: Concise way to create lists based on existing lists
- Syntax:
[expression for item in iterable if condition] - Benefits: More readable and efficient than traditional loops
List Comprehension Examples:
# Basic list comprehension
numbers = [i for i in range(10)] # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
squares = [x**2 for x in range(5)] # [0, 1, 4, 9, 16]
# With condition
even_numbers = [x for x in range(20) if x % 2 == 0] # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
odd_squares = [x**2 for x in range(10) if x % 2 == 1] # [1, 9, 25, 49, 81]
# String operations
word = "Python"
upper_letters = [char.upper() for char in word] # ['P', 'Y', 'T', 'H', 'O', 'N']
# Nested comprehension
matrix = [[i*j for j in range(3)] for i in range(3)]
# [[0, 0, 0], [0, 1, 2], [0, 2, 4]]
# Filtering and transforming
words = ["hello", "world", "python", "programming"]
long_words = [word.upper() for word in words if len(word) > 5]
# ['PYTHON', 'PROGRAMMING']
13. Tuples in Python
[image:2]
Tuples^13:
- Definition: Ordered, immutable sequences
- Creation: Parentheses
()or comma separation - Usage: Fixed collections, coordinates, database records
Tuple Operations:
# Creating tuples
coordinates = (10.0, 20.0)
colors = ("red", "green", "blue")
single_item = (42,) # Note the comma for single item
no_parentheses = 1, 2, 3 # Also creates tuple
# Accessing elements
print(coordinates[^0]) # 10.0
print(colors[-1]) # "blue"
# Tuple unpacking
x, y = coordinates
print(f"X: {x}, Y: {y}")
# Multiple assignment
a, b, c = colors
print(a, b, c) # red green blue
# Tuple methods
numbers = (1, 2, 3, 2, 2, 4)
print(numbers.count(2)) # 3 (occurrences of 2)
print(numbers.index(3)) # 2 (index of first 3)
# Tuples as dictionary keys
locations = {
(0, 0): "origin",
(1, 1): "northeast",
(-1, -1): "southwest"
}
# Named tuples (from collections module)
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
p = Point(3, 4)
print(p.x, p.y) # 3 4
14. Dictionaries in Python
[image:2]
Dictionaries^13:
- Definition: Key-value pairs for fast lookups
- Creation: Curly braces
{key: value} - Features: Mutable, unordered (Python 3.7+ maintains insertion order)
Dictionary Operations:
# Creating dictionaries
student = {"name": "Alice", "age": 23, "major": "Computer Science"}
empty_dict = {}
from_keys = dict.fromkeys(['a', 'b', 'c'], 0) # {'a': 0, 'b': 0, 'c': 0}
# Accessing values
print(student["name"]) # "Alice"
print(student.get("grade", "N/A")) # "N/A" (default if key not found)
# Modifying dictionaries
student["age"] = 24 # Update existing key
student["grade"] = "A" # Add new key-value pair
del student["major"] # Delete key-value pair
removed = student.pop("grade") # Remove and return value
# Dictionary methods
print(student.keys()) # dict_keys(['name', 'age'])
print(student.values()) # dict_values(['Alice', 24])
print(student.items()) # dict_items([('name', 'Alice'), ('age', 24)])
# Iterating through dictionaries
for key in student:
print(f"{key}: {student[key]}")
for key, value in student.items():
print(f"{key}: {value}")
# Dictionary comprehension
squares = {x: x**2 for x in range(5)} # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
even_squares = {x: x**2 for x in range(10) if x % 2 == 0}
# Nested dictionaries
students = {
"student1": {"name": "John", "grade": 85},
"student2": {"name": "Jane", "grade": 92}
}
print(students["student1"]["name"]) # "John"
15. Real World Use Cases of List
Data Processing:
# Processing sales data
sales = [1200, 1500, 980, 2100, 1750]
total_sales = sum(sales)
average_sales = total_sales / len(sales)
top_sales = max(sales)
# Finding above-average sales
above_average = [sale for sale in sales if sale > average_sales]
Inventory Management:
# Product inventory
inventory = [
{"name": "laptop", "quantity": 50, "price": 999.99},
{"name": "mouse", "quantity": 200, "price": 25.50},
{"name": "keyboard", "quantity": 75, "price": 79.99}
]
# Low stock items
low_stock = [item for item in inventory if item["quantity"] < 100]
# Total inventory value
total_value = sum(item["quantity"] * item["price"] for item in inventory)
Student Grade Management:
# Student grades
grades = [85, 92, 78, 96, 88, 73, 91]
# Statistical analysis
average_grade = sum(grades) / len(grades)
passing_grades = [grade for grade in grades if grade >= 70]
grade_distribution = {
'A': len([g for g in grades if g >= 90]),
'B': len([g for g in grades if 80 <= g < 90]),
'C': len([g for g in grades if 70 <= g < 80]),
'F': len([g for g in grades if g < 70])
}
Section 5: Functions in Python
16. Getting Started With Functions
Function Definition:
- Purpose: Reusable blocks of code that perform specific tasks
- Benefits: Code reusability, modularity, easier maintenance
- Syntax:
def function_name(parameters):
Basic Function Structure:
# Simple function
def greet():
print("Hello, World!")
greet() # Call the function
# Function with parameters
def greet_person(name):
print(f"Hello, {name}!")
greet_person("Alice") # Hello, Alice!
# Function with return value
def add_numbers(a, b):
result = a + b
return result
sum_result = add_numbers(5, 3) # Returns 8
# Function with default parameters
def greet_with_title(name, title="Mr./Ms."):
return f"Hello, {title} {name}!"
print(greet_with_title("Smith")) # Hello, Mr./Ms. Smith!
print(greet_with_title("Johnson", "Dr.")) # Hello, Dr. Johnson!
17. More Coding Examples With Functions
Functions with Multiple Parameters:
# Function with multiple parameters and return
def calculate_rectangle_area(length, width):
"""Calculate the area of a rectangle."""
area = length * width
return area
# Function with variable arguments (*args)
def sum_all(*numbers):
"""Sum all provided numbers."""
total = 0
for number in numbers:
total += number
return total
print(sum_all(1, 2, 3, 4, 5)) # 15
# Function with keyword arguments (**kwargs)
def create_profile(name, **details):
"""Create a user profile with flexible attributes."""
profile = {"name": name}
for key, value in details.items():
profile[key] = value
return profile
user = create_profile("Alice", age=25, city="New York", job="Engineer")
print(user) # {'name': 'Alice', 'age': 25, 'city': 'New York', 'job': 'Engineer'}
# Function returning multiple values
def get_name_parts(full_name):
"""Split full name into first and last name."""
parts = full_name.split()
first_name = parts[^0]
last_name = parts[-1] if len(parts) > 1 else ""
return first_name, last_name
first, last = get_name_parts("John Doe")
print(f"First: {first}, Last: {last}")
Practical Function Examples:
# Temperature conversion
def celsius_to_fahrenheit(celsius):
"""Convert Celsius to Fahrenheit."""
fahrenheit = (celsius * 9/5) + 32
return fahrenheit
def fahrenheit_to_celsius(fahrenheit):
"""Convert Fahrenheit to Celsius."""
celsius = (fahrenheit - 32) * 5/9
return celsius
# Validation function
def is_valid_email(email):
"""Basic email validation."""
return "@" in email and "." in email.split("@")[-1]
# Data processing function
def process_scores(scores):
"""Process a list of scores and return statistics."""
if not scores:
return None
stats = {
"count": len(scores),
"average": sum(scores) / len(scores),
"highest": max(scores),
"lowest": min(scores),
"passing": len([s for s in scores if s >= 60])
}
return stats
test_scores = [85, 92, 78, 96, 88, 73, 91]
results = process_scores(test_scores)
print(results)
18. Lambda Function in Python
Lambda Functions:
- Definition: Anonymous functions defined with
lambdakeyword - Syntax:
lambda arguments: expression - Usage: Short, simple functions for temporary use
- Limitations: Single expression only, no statements
Lambda Examples:
# Basic lambda function
square = lambda x: x ** 2
print(square(5)) # 25
# Lambda with multiple arguments
add = lambda x, y: x + y
print(add(3, 7)) # 10
# Lambda for string operations
full_name = lambda first, last: f"{first} {last}"
print(full_name("John", "Doe")) # John Doe
# Lambda with conditional expression
max_val = lambda a, b: a if a > b else b
print(max_val(10, 5)) # 10
# Using lambda in sorting
students = [("Alice", 85), ("Bob", 92), ("Charlie", 78)]
students.sort(key=lambda student: student[^1]) # Sort by grade
print(students) # [('Charlie', 78), ('Alice', 85), ('Bob', 92)]
19. Map Function in Python
Map Function^15:
- Purpose: Apply a function to every item in an iterable
- Syntax:
map(function, iterable) - Returns: Map object (iterator)
- Usage: Transform data without explicit loops
Map Examples:
# Basic map usage
numbers = [1, 2, 3, 4, 5]
squared = list(map(lambda x: x ** 2, numbers))
print(squared) # [1, 4, 9, 16, 25]
# Map with built-in functions
strings = ["1", "2", "3", "4", "5"]
integers = list(map(int, strings))
print(integers) # [1, 2, 3, 4, 5]
# Map with custom function
def celsius_to_fahrenheit(celsius):
return (celsius * 9/5) + 32
celsius_temps = [0, 20, 30, 40]
fahrenheit_temps = list(map(celsius_to_fahrenheit, celsius_temps))
print(fahrenheit_temps) # [32.0, 68.0, 86.0, 104.0]
# Map with multiple iterables
numbers1 = [1, 2, 3]
numbers2 = [4, 5, 6]
products = list(map(lambda x, y: x * y, numbers1, numbers2))
print(products) # [4, 10, 18]
# Map with string operations
words = ["hello", "world", "python"]
capitalized = list(map(str.upper, words))
print(capitalized) # ['HELLO', 'WORLD', 'PYTHON']
20. Filter Functions in Python
Filter Function^15:
- Purpose: Filter elements from iterable based on condition
- Syntax:
filter(function, iterable) - Returns: Filter object (iterator)
- Function: Should return True/False for each element
Filter Examples:
# Basic filter usage
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
even_numbers = list(filter(lambda x: x % 2 == 0, numbers))
print(even_numbers) # [2, 4, 6, 8, 10]
# Filter with custom function
def is_positive(n):
return n > 0
mixed_numbers = [-3, -1, 0, 2, 5, -8, 7]
positive_numbers = list(filter(is_positive, mixed_numbers))
print(positive_numbers) # [2, 5, 7]
# Filter strings
words = ["apple", "banana", "cherry", "date", "elderberry"]
long_words = list(filter(lambda word: len(word) > 5, words))
print(long_words) # ['banana', 'cherry', 'elderberry']
# Filter with None (removes falsy values)
mixed_data = [1, 0, "hello", "", None, "world", False, True]
truthy_values = list(filter(None, mixed_data))
print(truthy_values) # [1, 'hello', 'world', True]
# Complex filtering
students = [
{"name": "Alice", "grade": 85, "age": 20},
{"name": "Bob", "grade": 92, "age": 19},
{"name": "Charlie", "grade": 78, "age": 21},
{"name": "Diana", "grade": 95, "age": 20}
]
high_achievers = list(filter(lambda s: s["grade"] >= 90, students))
print([s["name"] for s in high_achievers]) # ['Bob', 'Diana']
Section 6: Importing, Creating Modules and Packages
21. Import Modules and Packages in Python
[image:2]
Module Basics^16:
- Definition: A file containing Python code (functions, classes, variables)
- Purpose: Code reusability and organization
- File Extension:
.py
Import Methods:
# Standard import
import math
print(math.sqrt(16)) # 4.0
# Import with alias
import numpy as np
array = np.array([1, 2, 3])
# Import specific functions
from math import sqrt, pi
print(sqrt(25)) # 5.0
print(pi) # 3.141592653589793
# Import all (not recommended)
from math import *
# Import from subdirectory
from mypackage import mymodule
from mypackage.subpackage import utilities
Creating Custom Modules^17:
# mymodule.py
def greet(name):
return f"Hello, {name}!"
def add(a, b):
return a + b
PI = 3.14159
# Using the module
# main.py
import mymodule
print(mymodule.greet("World")) # Hello, World!
print(mymodule.add(5, 3)) # 8
print(mymodule.PI) # 3.14159
22. Standard Libraries Overview in Python
[image:2]
Essential Standard Libraries^18:
File and System Operations:
- os: Operating system interface, file paths, environment variables
- sys: System-specific parameters and functions
- pathlib: Object-oriented path handling
- shutil: High-level file operations (copy, move, delete)
Data Processing:
- json: JSON encoder and decoder
- csv: CSV file reading and writing
- sqlite3: SQLite database interface
- pickle: Python object serialization
Date and Time:
- datetime: Date and time manipulation
- time: Time-related functions
- calendar: Calendar-related functions
Examples:
# os module
import os
print(os.getcwd()) # Current working directory
print(os.listdir('.')) # List directory contents
os.makedirs('new_folder', exist_ok=True)
# datetime module
from datetime import datetime, date, timedelta
now = datetime.now()
today = date.today()
tomorrow = today + timedelta(days=1)
print(f"Today: {today}, Tomorrow: {tomorrow}")
# json module
import json
data = {"name": "Alice", "age": 25}
json_string = json.dumps(data)
parsed_data = json.loads(json_string)
# random module
import random
print(random.randint(1, 10)) # Random integer between 1 and 10
print(random.choice(['a', 'b', 'c'])) # Random choice from list
# math module
import math
print(math.factorial(5)) # 120
print(math.gcd(12, 18)) # 6
print(math.degrees(math.pi)) # 180.0
Advanced Libraries:
# collections module
from collections import Counter, defaultdict, namedtuple
count = Counter("hello world")
print(count) # Counter({'l': 3, 'o': 2, 'h': 1, 'e': 1, ' ': 1, 'w': 1, 'r': 1, 'd': 1})
# itertools module
import itertools
numbers = [1, 2, 3]
permutations = list(itertools.permutations(numbers))
print(permutations) # [(1, 2, 3), (1, 3, 2), (2, 1, 3), (2, 3, 1), (3, 1, 2), (3, 2, 1)]
# functools module
from functools import reduce
numbers = [1, 2, 3, 4, 5]
product = reduce(lambda x, y: x * y, numbers)
print(product) # 120
Section 7: File Handling in Python
23. File Operations With Python
[image:3]
File Opening Modes^19:
- 'r': Read mode (default)
- 'w': Write mode (overwrites existing file)
- 'a': Append mode
- 'x': Exclusive creation (fails if file exists)
- 'b': Binary mode (e.g., 'rb', 'wb')
- 't': Text mode (default)
Basic File Operations:
# Writing to a file
with open('example.txt', 'w') as file:
file.write("Hello, World!\n")
file.write("This is a new line.\n")
# Reading entire file
with open('example.txt', 'r') as file:
content = file.read()
print(content)
# Reading line by line
with open('example.txt', 'r') as file:
for line in file:
print(line.strip()) # strip() removes newline characters
# Reading specific number of characters
with open('example.txt', 'r') as file:
first_10_chars = file.read(10)
print(first_10_chars)
# Appending to file
with open('example.txt', 'a') as file:
file.write("This line is appended.\n")
File Handling Best Practices:
# Using context manager (with statement) - recommended
with open('data.txt', 'r') as file:
data = file.read()
# File automatically closed after with block
# Manual file handling (not recommended)
file = open('data.txt', 'r')
data = file.read()
file.close() # Must remember to close
# Error handling with files
try:
with open('nonexistent.txt', 'r') as file:
content = file.read()
except FileNotFoundError:
print("File not found!")
except PermissionError:
print("Permission denied!")
Working with CSV Files:
import csv
# Writing CSV
data = [
['Name', 'Age', 'City'],
['Alice', 25, 'New York'],
['Bob', 30, 'London'],
['Charlie', 35, 'Paris']
]
with open('people.csv', 'w', newline='') as file:
writer = csv.writer(file)
writer.writerows(data)
# Reading CSV
with open('people.csv', 'r') as file:
reader = csv.reader(file)
for row in reader:
print(row)
# Working with CSV as dictionaries
with open('people.csv', 'r') as file:
reader = csv.DictReader(file)
for row in reader:
print(f"Name: {row['Name']}, Age: {row['Age']}")
24. Working with File Paths
[image:3]
Path Handling^20:
- os.path: Traditional path manipulation
- pathlib: Modern, object-oriented approach (Python 3.4+)
- Cross-platform: Handles Windows/Unix differences automatically
Using pathlib (Recommended):
from pathlib import Path
# Creating paths
current_dir = Path.cwd() # Current working directory
home_dir = Path.home() # User home directory
file_path = Path('documents/file.txt')
# Path operations
print(file_path.name) # 'file.txt'
print(file_path.stem) # 'file'
print(file_path.suffix) # '.txt'
print(file_path.parent) # 'documents'
# Joining paths
project_path = Path('projects') / 'my_project' / 'src' / 'main.py'
print(project_path)
# Checking path properties
if file_path.exists():
print("File exists")
if file_path.is_file():
print("It's a file")
if file_path.is_dir():
print("It's a directory")
# Creating directories
new_dir = Path('new_folder')
new_dir.mkdir(exist_ok=True) # exist_ok=True prevents error if exists
# Listing directory contents
for item in Path('.').iterdir():
if item.is_file():
print(f"File: {item.name}")
else:
print(f"Directory: {item.name}")
Using os.path (Traditional):
import os
# Path operations
current_dir = os.getcwd()
file_path = os.path.join('documents', 'file.txt')
# Path information
print(os.path.basename(file_path)) # 'file.txt'
print(os.path.dirname(file_path)) # 'documents'
print(os.path.splitext(file_path)) # ('documents/file', '.txt')
# Checking paths
if os.path.exists(file_path):
print("Path exists")
if os.path.isfile(file_path):
print("It's a file")
if os.path.isdir(file_path):
print("It's a directory")
# Creating directories
os.makedirs('new_folder', exist_ok=True)
# Listing directory
for item in os.listdir('.'):
full_path = os.path.join('.', item)
if os.path.isfile(full_path):
print(f"File: {item}")
else:
print(f"Directory: {item}")
Section 8: Exception Handling
25. Exception Handling With try except else and finally blocks
[image:3]
Exception Handling Structure^21:
- try: Test block of code for errors
- except: Handle specific errors
- else: Execute when no errors occur
- finally: Always execute (cleanup code)
Basic Exception Handling:
# Simple try-except
try:
result = 10 / 0
except ZeroDivisionError:
print("Cannot divide by zero!")
# Multiple exception types
try:
num = int(input("Enter a number: "))
result = 10 / num
print(f"Result: {result}")
except ValueError:
print("Invalid input! Please enter a number.")
except ZeroDivisionError:
print("Cannot divide by zero!")
# Generic exception handling
try:
# Some risky operation
file = open('nonexistent.txt', 'r')
except Exception as e:
print(f"An error occurred: {e}")
Complete Exception Handling:
def divide_numbers(a, b):
try:
result = a / b
except ZeroDivisionError:
print("Error: Division by zero!")
return None
except TypeError:
print("Error: Invalid data types!")
return None
else:
print("Division successful!")
return result
finally:
print("Division operation completed.")
# Testing the function
print(divide_numbers(10, 2)) # Successful division
print(divide_numbers(10, 0)) # Division by zero
print(divide_numbers(10, "2")) # Type error
File Handling with Exception Handling:
def read_file_safely(filename):
try:
with open(filename, 'r') as file:
content = file.read()
return content
except FileNotFoundError:
print(f"Error: File '{filename}' not found.")
return None
except PermissionError:
print(f"Error: Permission denied to access '{filename}'.")
return None
except Exception as e:
print(f"Unexpected error: {e}")
return None
else:
print("File read successfully!")
finally:
print("File operation completed.")
# Usage
content = read_file_safely('example.txt')
if content:
print(content)
Custom Exception Handling:
# Custom exception class
class InvalidAgeError(Exception):
"""Custom exception for invalid age values."""
pass
def validate_age(age):
try:
age = int(age)
if age < 0:
raise InvalidAgeError("Age cannot be negative!")
elif age > 150:
raise InvalidAgeError("Age seems unrealistic!")
return age
except ValueError:
raise InvalidAgeError("Age must be a number!")
# Using custom exception
try:
user_age = validate_age("25")
print(f"Valid age: {user_age}")
invalid_age = validate_age("-5")
except InvalidAgeError as e:
print(f"Age validation error: {e}")
Section 9: OOPS Classes and Objects
26. Classes and Objects in Python
[image:3]
Object-Oriented Programming Concepts:
- Class: Blueprint for creating objects
- Object: Instance of a class
- Attributes: Variables that belong to a class/object
- Methods: Functions that belong to a class
Basic Class Definition:
class Person:
# Class attribute (shared by all instances)
species = "Homo sapiens"
def __init__(self, name, age):
# Instance attributes (unique to each object)
self.name = name
self.age = age
def introduce(self):
return f"Hi, I'm {self.name} and I'm {self.age} years old."
def have_birthday(self):
self.age += 1
return f"Happy birthday! {self.name} is now {self.age}."
# Creating objects (instances)
person1 = Person("Alice", 25)
person2 = Person("Bob", 30)
# Accessing attributes and methods
print(person1.name) # Alice
print(person1.introduce()) # Hi, I'm Alice and I'm 25 years old.
print(person1.have_birthday()) # Happy birthday! Alice is now 26.
# Class attribute access
print(person1.species) # Homo sapiens
print(Person.species) # Homo sapiens
More Complex Class Example:
class BankAccount:
# Class attribute
bank_name = "Python Bank"
def __init__(self, account_holder, initial_balance=0):
self.account_holder = account_holder
self.balance = initial_balance
self.transaction_history = []
def deposit(self, amount):
if amount > 0:
self.balance += amount
self.transaction_history.append(f"Deposited ${amount}")
return f"${amount} deposited. New balance: ${self.balance}"
else:
return "Invalid deposit amount."
def withdraw(self, amount):
if amount > 0 and amount <= self.balance:
self.balance -= amount
self.transaction_history.append(f"Withdrew ${amount}")
return f"${amount} withdrawn. New balance: ${self.balance}"
else:
return "Invalid withdrawal amount or insufficient funds."
def get_balance(self):
return f"Current balance: ${self.balance}"
def get_transaction_history(self):
return self.transaction_history
# Using the class
account = BankAccount("John Doe", 1000)
print(account.deposit(500)) # $500 deposited. New balance: $1500
print(account.withdraw(200)) # $200 withdrawn. New balance: $1300
print(account.get_balance()) # Current balance: $1300
print(account.get_transaction_history()) # ['Deposited $500', 'Withdrew $200']
27. Single and Multiple Inheritance
[image:3]
Single Inheritance^22:
- Definition: Child class inherits from one parent class
- Syntax:
class Child(Parent): - Benefits: Code reuse, hierarchical organization
Single Inheritance Example:
# Parent class
class Animal:
def __init__(self, name, species):
self.name = name
self.species = species
def make_sound(self):
return f"{self.name} makes a sound."
def info(self):
return f"{self.name} is a {self.species}."
# Child class inheriting from Animal
class Dog(Animal):
def __init__(self, name, breed):
super().__init__(name, "Dog") # Call parent constructor
self.breed = breed
def make_sound(self): # Method overriding
return f"{self.name} barks: Woof!"
def fetch(self): # New method specific to Dog
return f"{self.name} fetches the ball!"
# Using inheritance
my_dog = Dog("Buddy", "Golden Retriever")
print(my_dog.info()) # Buddy is a Dog.
print(my_dog.make_sound()) # Buddy barks: Woof!
print(my_dog.fetch()) # Buddy fetches the ball!
Multiple Inheritance:
- Definition: Child class inherits from multiple parent classes
- Syntax:
class Child(Parent1, Parent2): - Method Resolution Order (MRO): Determines which method is called
Multiple Inheritance Example:
class Flyable:
def fly(self):
return "Flying through the air!"
class Swimmable:
def swim(self):
return "Swimming in water!"
class Duck(Animal, Flyable, Swimmable):
def __init__(self, name):
super().__init__(name, "Duck")
def make_sound(self):
return f"{self.name} quacks: Quack!"
# Using multiple inheritance
duck = Duck("Donald")
print(duck.info()) # Donald is a Duck.
print(duck.make_sound()) # Donald quacks: Quack!
print(duck.fly()) # Flying through the air!
print(duck.swim()) # Swimming in water!
# Check Method Resolution Order
print(Duck.__mro__) # Shows the order of method resolution
28. Polymorphism in OOPS
Polymorphism^23:
- Definition: Same interface, different implementations
- Types: Method overriding, duck typing
- Benefit: Code flexibility and extensibility
Polymorphism Examples:
# Base class
class Shape:
def area(self):
raise NotImplementedError("Subclass must implement area method")
def perimeter(self):
raise NotImplementedError("Subclass must implement perimeter method")
# Different shapes with same interface
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
def perimeter(self):
return 2 * (self.width + self.height)
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14159 * self.radius ** 2
def perimeter(self):
return 2 * 3.14159 * self.radius
class Triangle(Shape):
def __init__(self, base, height, side1, side2, side3):
self.base = base
self.height = height
self.side1 = side1
self.side2 = side2
self.side3 = side3
def area(self):
return 0.5 * self.base * self.height
def perimeter(self):
return self.side1 + self.side2 + self.side3
# Polymorphism in action
def print_shape_info(shape):
"""Function that works with any shape object"""
print(f"Area: {shape.area():.2f}")
print(f"Perimeter: {shape.perimeter():.2f}")
print("-" * 20)
# Using polymorphism
shapes = [
Rectangle(5, 3),
Circle(4),
Triangle(6, 4, 5, 5, 6)
]
for shape in shapes:
print_shape_info(shape)
29. Encapsulation in OOPS
Encapsulation^23:
- Definition: Bundling data and methods, controlling access
- Private attributes: Single underscore
_(convention), double underscore__(name mangling) - Property decorators:
@property,@setter,@deleter
Encapsulation Examples:
class Student:
def __init__(self, name, age):
self._name = name # Protected attribute (convention)
self.__age = age # Private attribute (name mangling)
self.__grades = [] # Private list
@property
def name(self):
"""Getter for name"""
return self._name
@name.setter
def name(self, value):
"""Setter for name with validation"""
if isinstance(value, str) and len(value) > 0:
self._name = value
else:
raise ValueError("Name must be a non-empty string")
@property
def age(self):
"""Getter for age"""
return self.__age
@age.setter
def age(self, value):
"""Setter for age with validation"""
if isinstance(value, int) and 0 <= value <= 150:
self.__age = value
else:
raise ValueError("Age must be between 0 and 150")
def add_grade(self, grade):
"""Public method to add grade"""
if 0 <= grade <= 100:
self.__grades.append(grade)
else:
raise ValueError("Grade must be between 0 and 100")
def get_average_grade(self):
"""Public method to get average grade"""
if self.__grades:
return sum(self.__grades) / len(self.__grades)
return 0
def get_grades(self):
"""Public method to get copy of grades"""
return self.__grades.copy() # Return copy to prevent direct modification
# Using encapsulation
student = Student("Alice", 20)
# Using property
print(student.name) # Alice
student.name = "Alice Smith"
print(student.name) # Alice Smith
# Accessing age through property
print(student.age) # 20
student.age = 21
print(student.age) # 21
# Adding grades
student.add_grade(85)
student.add_grade(92)
student.add_grade(78)
print(f"Average grade: {student.get_average_grade():.2f}") # Average grade: 85.00
print(f"Grades: {student.get_grades()}") # Grades: [85, 92, 78]
# Attempting direct access to private attribute
# print(student.__age) # This would raise AttributeError
# But can access via name mangling (not recommended):
# print(student._Student__age) # 21
30. Abstraction in OOPS
Abstraction^23:
- Definition: Hide implementation details, show only essential features
- Abstract Base Classes: Use
abcmodule - Abstract methods: Must be implemented by subclasses
Abstraction Examples:
from abc import ABC, abstractmethod
class Vehicle(ABC):
"""Abstract base class for vehicles"""
def __init__(self, brand, model):
self.brand = brand
self.model = model
@abstractmethod
def start_engine(self):
"""Abstract method - must be implemented by subclasses"""
pass
@abstractmethod
def stop_engine(self):
"""Abstract method - must be implemented by subclasses"""
pass
def get_info(self):
"""Concrete method available to all subclasses"""
return f"{self.brand} {self.model}"
class Car(Vehicle):
def __init__(self, brand, model, num_doors):
super().__init__(brand, model)
self.num_doors = num_doors
def start_engine(self):
return f"{self.get_info()} car engine started with ignition key."
def stop_engine(self):
return f"{self.get_info()} car engine stopped."
def open_doors(self):
return f"Opening {self.num_doors} doors."
class Motorcycle(Vehicle):
def __init__(self, brand, model, engine_size):
super().__init__(brand, model)
self.engine_size = engine_size
def start_engine(self):
return f"{self.get_info()} motorcycle engine started with kick/button."
def stop_engine(self):
return f"{self.get_info()} motorcycle engine stopped."
def wheelie(self):
return f"{self.get_info()} doing a wheelie!"
# Using abstraction
# vehicle = Vehicle("Generic", "Model") # This would raise TypeError
car = Car("Toyota", "Camry", 4)
motorcycle = Motorcycle("Honda", "CBR", "600cc")
print(car.start_engine()) # Toyota Camry car engine started with ignition key.
print(car.open_doors()) # Opening 4 doors.
print(motorcycle.start_engine()) # Honda CBR motorcycle engine started with kick/button.
print(motorcycle.wheelie()) # Honda CBR doing a wheelie!
# Polymorphism with abstract classes
vehicles = [car, motorcycle]
for vehicle in vehicles:
print(vehicle.start_engine())
print(vehicle.stop_engine())
31. Magic Methods in Python
Magic Methods (Dunder Methods)^24:
- Definition: Special methods with double underscores
- Purpose: Define how objects behave with built-in operations
- Automatic invocation: Called by Python interpreter
Common Magic Methods:
class Book:
def __init__(self, title, author, pages):
self.title = title
self.author = author
self.pages = pages
def __str__(self):
"""String representation for end users"""
return f"{self.title} by {self.author}"
def __repr__(self):
"""String representation for developers"""
return f"Book('{self.title}', '{self.author}', {self.pages})"
def __len__(self):
"""Return length (number of pages)"""
return self.pages
def __eq__(self, other):
"""Define equality comparison"""
if isinstance(other, Book):
return (self.title == other.title and
self.author == other.author)
return False
def __lt__(self, other):
"""Define less than comparison (by pages)"""
if isinstance(other, Book):
return self.pages < other.pages
return NotImplemented
def __add__(self, other):
"""Define addition (combine pages)"""
if isinstance(other, Book):
return self.pages + other.pages
return NotImplemented
# Using magic methods
book1 = Book("1984", "George Orwell", 328)
book2 = Book("Animal Farm", "George Orwell", 112)
book3 = Book("1984", "George Orwell", 328)
print(str(book1)) # 1984 by George Orwell (__str__)
print(repr(book1)) # Book('1984', 'George Orwell', 328) (__repr__)
print(len(book1)) # 328 (__len__)
print(book1 == book3) # True (__eq__)
print(book1 < book2) # False (__lt__)
print(book1 + book2) # 440 (__add__)
32. Operator Overloading in Python
Operator Overloading^26:
- Definition: Giving additional meanings to operators for custom classes
- Magic Methods: Use dunder methods to define operator behavior
- Benefits: Natural, intuitive operations on custom objects
Comprehensive Operator Overloading Example:
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return f"Vector({self.x}, {self.y})"
def __repr__(self):
return f"Vector({self.x}, {self.y})"
# Arithmetic operators
def __add__(self, other):
"""Addition: v1 + v2"""
if isinstance(other, Vector):
return Vector(self.x + other.x, self.y + other.y)
return NotImplemented
def __sub__(self, other):
"""Subtraction: v1 - v2"""
if isinstance(other, Vector):
return Vector(self.x - other.x, self.y - other.y)
return NotImplemented
def __mul__(self, scalar):
"""Scalar multiplication: v * scalar"""
if isinstance(scalar, (int, float)):
return Vector(self.x * scalar, self.y * scalar)
return NotImplemented
def __rmul__(self, scalar):
"""Right scalar multiplication: scalar * v"""
return self.__mul__(scalar)
def __truediv__(self, scalar):
"""Division: v / scalar"""
if isinstance(scalar, (int, float)) and scalar != 0:
return Vector(self.x / scalar, self.y / scalar)
return NotImplemented
# Comparison operators
def __eq__(self, other):
"""Equality: v1 == v2"""
if isinstance(other, Vector):
return self.x == other.x and self.y == other.y
return False
def __lt__(self, other):
"""Less than: v1 < v2 (by magnitude)"""
if isinstance(other, Vector):
return self.magnitude() < other.magnitude()
return NotImplemented
# Unary operators
def __neg__(self):
"""Negation: -v"""
return Vector(-self.x, -self.y)
def __abs__(self):
"""Absolute value: abs(v) - magnitude"""
return self.magnitude()
# Helper method
def magnitude(self):
"""Calculate vector magnitude"""
return (self.x ** 2 + self.y ** 2) ** 0.5
# Using operator overloading
v1 = Vector(3, 4)
v2 = Vector(1, 2)
print(f"v1: {v1}") # v1: Vector(3, 4)
print(f"v2: {v2}") # v2: Vector(1, 2)
print(f"v1 + v2: {v1 + v2}") # v1 + v2: Vector(4, 6)
print(f"v1 - v2: {v1 - v2}") # v1 - v2: Vector(2, 2)
print(f"v1 * 2: {v1 * 2}") # v1 * 2: Vector(6, 8)
print(f"3 * v2: {3 * v2}") # 3 * v2: Vector(3, 6)
print(f"v1 / 2: {v1 / 2}") # v1 / 2: Vector(1.5, 2.0)
print(f"v1 == v2: {v1 == v2}") # v1 == v2: False
print(f"v1 < v2: {v1 < v2}") # v1 < v2: False
print(f"-v1: {-v1}") # -v1: Vector(-3, -4)
print(f"abs(v1): {abs(v1)}") # abs(v1): 5.0
This comprehensive revision guide covers all the Python topics shown in your images, providing detailed explanations, practical examples, and best practices for each concept. Each section includes crisp, bullet-pointed notes with working code examples that demonstrate the usage of each Python feature.