Core Python - Modules 14-17
Core Python - Modules 14-17
In Python, the import statement is used to bring modules, packages, or specific components of
modules into your code, so you can use their functions, classes, and variables. Here's how you
can work with it:
import math
● You can now use the math module by prefixing its functions or constants with math.:
● Now you can directly use sqrt and pi without the math. prefix:
3. Using Aliases
a. Aliasing Modules:
import numpy as np
4. Importing Everything
● This brings all components of the module into your code's namespace:
Caution: This method may lead to namespace pollution, causing conflicts with existing
variables or functions.
# my_module.py
def greet():
return "Hello, World!"
import my_module
print(my_module.greet()) # Output: Hello, World!
import importlib
math_module = importlib.import_module('math')
print(math_module.sqrt(16)) # Output: 4.0
Best Practices
● Use specific imports (from module import component) for clarity and
efficiency.
● Use aliases to improve readability for long module names.
● Avoid using from module import * in large projects.
2. Modules and Packages in Python
In Python, modules and packages are ways to structure and organize code into reusable
components.
1. Modules
A module is a single Python file containing definitions, functions, classes, and executable code.
Modules help you organize and reuse code by breaking it into smaller, manageable files.
Example:
# my_module.py
def greet(name):
return f"Hello, {name}!"
def add(a, b):
return a + b
# main.py
import my_module
print(my_module.greet("Alice")) # Output: Hello, Alice!
print(my_module.add(5, 3)) # Output: 8
Types of Module Imports
import my_module
print(my_module.greet("Alice"))
b. Import specific functions or classes:
import my_module as mm
print(mm.greet("Alice"))
2. Packages
A package is a directory containing a special __init__.py file and one or more module files.
It is used to organize related modules into a hierarchy.
Structure of a Package
mypackage/
__init__.py
module1.py
module2.py
Purpose of __init__.py
The __init__.py file can be empty, or it can include initialization code for the package. It
makes Python treat the directory as a package.
Creating a Package
Directory Structure:
mypackage/
__init__.py
greetings.py
calculations.py
def say_hello(name):
return f"Hello, {name}!"
You can use relative imports within a package to import from sibling modules.
Example:
# mypackage/calculations.py
from .greetings import say_hello
def greet_and_add(name, a, b):
greeting = say_hello(name)
total = a + b
return f"{greeting} The sum is {total}."
Built-in and Third-Party Modules
Built-in Modules
Python includes many pre-installed modules like os, sys, math, datetime, etc.
import math
print(math.sqrt(16)) # Output: 4.0
Third-Party Modules
These are installed via pip (Python Package Installer). For example:
Usage:
import requests
response = requests.get('https://example.com')
print(response.status_code)
Purpose Organize code into a single file Organize multiple modules into a folder
Best Practices
1. Use packages to structure large projects.
2. Follow naming conventions: use lowercase for module and package names.
3. Keep modules focused on a single responsibility.
4. Document your modules and packages clearly.
The calendar module in Python provides functions for working with calendars and dates. It
includes methods for creating, manipulating, and formatting calendar data, making it useful for
date-related operations.
Text Calendar
import calendar
# Print a text calendar for a specific month
print(calendar.month(2024, 12))
# Print a text calendar for a whole year
print(calendar.calendar(2024))
Output:
December 2024
Mo Tu We Th Fr Sa Su
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
HTML Calendar
html_calendar = calendar.HTMLCalendar()
html_code = html_calendar.formatmonth(2024, 12)
print(html_code)
Weekday Constants
● calendar.MONDAY = 0
● calendar.SUNDAY = 6
is_leap = calendar.isleap(2024)
print(is_leap) # Output: True
Count Leap Years in a Range
Example:
[0, 0, 0, 0, 0, 0, 1]
[2, 3, 4, 5, 6, 7, 8]
[9, 10, 11, 12, 13, 14, 15]
[16, 17, 18, 19, 20, 21, 22]
[23, 24, 25, 26, 27, 28, 29]
[30, 31, 0, 0, 0, 0, 0]
d. Customize Calendar Start Day
calendar.setfirstweekday(calendar.SUNDAY)
print(calendar.month(2024, 12))
c = calendar.Calendar()
for day in c.iterweekdays():
print(day) # Outputs day numbers for a week starting from
MONDAY
3. Practical Examples
Scenario: You want to display the first weekday of every month for the year 2024 to decide
which months begin with a Monday.
import calendar
year = 2024
if first_day == calendar.MONDAY:
print(f"{calendar.month_name[month]} starts on a
Monday.")
Output:
The calendar module is versatile and highly useful for scheduling, formatting dates, and
date-related computations.
In Python, the random module provides tools for generating random numbers and performing
randomization tasks. Here's how you can work with it effectively.
import random
● random(): Generates a random float between 0.0 (inclusive) and 1.0 (exclusive).
b. Random Integers
● randint(a, b): Returns a random integer between a and b (inclusive).
c. Random Boolean
b. Shuffle a List
numbers = [1, 2, 3, 4, 5]
random.shuffle(numbers)
print(numbers) # Output: [4, 1, 5, 2, 3] (example)
numbers = [1, 2, 3, 4, 5]
print(random.sample(numbers, 3)) # Output: [2, 4, 1] (example)
a. Normal Distribution
b. Exponential Distribution
c. Uniform Distribution
5. Controlling Randomness
The random module generates pseudo-random numbers based on a seed. You can set the seed to
make results reproducible:
random.seed(42)
print(random.random()) # Output: 0.6394267984578837 (consistent
for the same seed)
import secrets
# Generate a secure random number
print(secrets.randbelow(10)) # Output: 7 (example)
# Generate a secure random token
print(secrets.token_hex(16)) # Output:
'a7e1c2e3f68d9ac3b4d2d234' (example)
The numpy.random module is more powerful for working with arrays and complex
distributions.
import numpy as np
# Generate an array of random numbers
print(np.random.rand(3)) # Output: [0.3744, 0.9507, 0.7320]
(example)
# Random integer array
print(np.random.randint(0, 10, size=(2, 3))) # Output: 2D array
of random integers
Examples
Generate a Random Password
import random
import string
length = 8
password = ''.join(random.choices(string.ascii_letters +
string.digits, k=length))
print(password) # Output: 'a2Bd5Fg7' (example)
dice_roll = random.randint(1, 6)
print(f"You rolled a {dice_roll}") # Output: 'You rolled a 4'
(example)
Scenario: Simulate a lottery draw where 6 unique numbers are drawn from a range of 1 to 49.
import random
lottery_numbers = random.sample(range(1, 50), 6)
print(f"Lottery numbers: {sorted(lottery_numbers)}")
Scenario: A teacher wants to randomize the seating arrangement for 5 students in a row.
import random
students = ['John', 'Emily', 'Sophia', 'Liam', 'Noah']
random.shuffle(students)
print(f"Randomized seating: {students}")
import random
weather_conditions = ['Sunny', 'Rainy', 'Cloudy']
weekly_weather = [random.choice(weather_conditions) for _ in
range(7)]
print(f"Weekly weather: {weekly_weather}")
Python provides several modules for working with dates and times, with the most commonly
used ones being datetime and time. Here's how you can work with dates in Python:
You can get the current date and time using the datetime.now() function.
current_datetime = datetime.now()
Output (Example):
To get just the current date (without time), use the date() method:
from datetime import datetime
current_date = datetime.now().date()
Output (Example):
You can create a datetime object for a specific date using datetime(year, month,
day):
Output:
timedelta objects represent differences in dates and times. You can add or subtract days,
hours, etc., from a datetime.
Output (Example):
Output:
3. Formatting Dates
You can format datetime objects into human-readable strings using strftime().
a. Custom Date Format
current_datetime = datetime.now()
Output (Example):
You can extract specific parts of a date or time, like the day of the week, year, month, etc.
current_datetime = datetime.now()
print("Year:", current_datetime.year)
print("Month:", current_datetime.month)
print("Day:", current_datetime.day)
print("Hour:", current_datetime.hour)
print("Minute:", current_datetime.minute)
print("Second:", current_datetime.second)
Output (Example):
Year: 2024
Month: 12
Day: 21
Hour: 14
Minute: 55
Second: 23
You can also work with just the date class from the datetime module if you don’t need the
time part.
Output:
today = date.today()
You can also work with just the time class to manipulate times.
Output:
current_time = datetime.now().time()
Output (Example):
You can convert a string representation of a date into a datetime object using strptime().
from datetime import datetime
Output:
You can also use the calendar module to perform various date-related tasks.
import calendar
year = 2024
if calendar.isleap(year):
else:
Output:
import calendar
year = 2024
month = 12
print(calendar.month(year, month))
Output:
December 2024
Mo Tu We Th Fr Sa Su
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
Scenario: Convert the current time in UTC to a specified time zone (e.g., New York or Tokyo).
import datetime
import pytz
# Get current time in UTC
utc_time = datetime.datetime.now(pytz.utc)
print("UTC Time:", utc_time)
Output (Example):
Scenario: Schedule a meeting 3 hours from now and display the scheduled time in multiple time
zones.
import datetime
import pytz
tokyo_tz = pytz.timezone('Asia/Tokyo')
tokyo_time = future_time.astimezone(tokyo_tz)
new_york_tz = pytz.timezone('America/New_York')
new_york_time = future_time.astimezone(new_york_tz)
Output (Example):
import datetime
import pytz
print(f"Event: {event_name}")
print(f"Time: {local_time.strftime('%Y-%m-%d %H:%M:%S
%Z%z')}")
Output (Example):
To read data from a JSON file, use json.load() to parse the contents into a Python
dictionary or list.
import json
{
"name": "John Doe",
"age": 30,
"city": "New York"
}
Output:
import json
# Python dictionary
data = {
"name": "Jane Smith",
"age": 28,
"city": "Los Angeles"
}
Sometimes, you may want to convert a Python object to a JSON-formatted string without writing
it to a file. You can use json.dumps() for this.
import json
# Python dictionary
data = {
"name": "Alice",
"age": 25,
"city": "Seattle"
}
Output:
{
"name": "Alice",
"age": 25,
"city": "Seattle"
}
If you have a JSON-formatted string, you can parse it into a Python object using
json.loads().
import json
# JSON string
json_string = '{"name": "Bob", "age": 22, "city": "Chicago"}'
Output:
You can pretty-print JSON data using json.dumps() with the indent argument, which
makes the output more readable.
import json
# Python dictionary
data = {
"name": "Charlie",
"age": 35,
"city": "San Francisco",
"skills": ["Python", "Data Analysis", "Machine Learning"]
}
# Pretty print the JSON data
pretty_json = json.dumps(data, indent=4)
print(pretty_json)
Output:
{
"name": "Charlie",
"age": 35,
"city": "San Francisco",
"skills": [
"Python",
"Data Analysis",
"Machine Learning"
]
}
If the JSON data contains nested structures (like lists or dictionaries within dictionaries), it can
be accessed and manipulated similarly.
Example:
import json
# JSON with nested data
data = {
"name": "David",
"age": 40,
"address": {
"street": "123 Main St",
"city": "Boston",
"zipcode": "02101"
},
"phone_numbers": ["555-1234", "555-5678"]
}
# Convert the data to a JSON string with indentation
json_string = json.dumps(data, indent=4)
print(json_string)
Output:
{
"name": "David",
"age": 40,
"address": {
"street": "123 Main St",
"city": "Boston",
"zipcode": "02101"
},
"phone_numbers": [
"555-1234",
"555-5678"
]
}
When reading or parsing JSON, you might encounter errors, such as invalid JSON syntax. You
can handle these errors using try and except.
import json
You can update specific values in a loaded JSON object just like you would with any dictionary
in Python.
import json
# Sample JSON data
data = {
"name": "Eve",
"age": 30,
"city": "Paris"
}
# Update a value
data["city"] = "Berlin"
You can create a function to read a JSON file, manipulate the data, and write it back.
import json
def update_age(filename, new_age):
with open(filename, 'r') as file:
data = json.load(file)
Python provides built-in support for reading from and writing to CSV files through the csv
module. Additionally, you can use the pandas library for more advanced handling of CSV data.
To read a CSV file, you can use csv.reader() or csv.DictReader() to load the data
into a list of dictionaries.
import csv
# Read CSV file
with open('data.csv', 'r') as file:
csv_reader = csv.reader(file)
for row in csv_reader:
print(row)
Example of data.csv:
name,age,city
John,30,New York
Jane,28,Los Angeles
Alice,25,Seattle
Output:
import csv
name,age,city
John,30,New York
Jane,28,Los Angeles
Alice,25,Seattle
pandas is a powerful library that makes it easier to work with CSV files, especially when
dealing with large datasets or complex operations.
import pandas as pd
# Read CSV file into DataFrame
df = pd.read_csv('data.csv')
print(df)
Output:
import pandas as pd
# Create DataFrame
df = pd.DataFrame({
"name": ["John", "Jane", "Alice"],
"age": [30, 28, 25],
"city": ["New York", "Los Angeles", "Seattle"]
})
name,age,city
John,30,New York
Jane,28,Los Angeles
Alice,25,Seattle
For handling Excel files, you can use libraries like openpyxl (for .xlsx files) or pandas
(for both .xls and .xlsx files).
Example of data.xlsx:
Alice 25 Seattle
Output:
pandas makes working with Excel files even simpler and more versatile.
import pandas as pd
# Read Excel file into DataFrame
df = pd.read_excel('data.xlsx')
print(df)
Output:
import pandas as pd
# Create two DataFrames for different sheets
df1 = pd.DataFrame({
"name": ["John", "Jane"],
"age": [30, 28],
"city": ["New York", "Los Angeles"]
})
df2 = pd.DataFrame({
"name": ["Alice", "Bob"],
"age": [25, 35],
"city": ["Seattle", "Chicago"]
})
# Write DataFrames to different sheets
with pd.ExcelWriter('multi_sheet_output.xlsx') as writer:
df1.to_excel(writer, sheet_name='Sheet1', index=False)
df2.to_excel(writer, sheet_name='Sheet2', index=False)
You can read, modify, and save an Excel file using openpyxl or pandas.
Using openpyxl:
Using pandas:
import pandas as pd
# Read the Excel file into DataFrame
df = pd.read_excel('data.xlsx')
# Modify a value (change 'John' to 'Michael')
df.loc[df['name'] == 'John', 'name'] = 'Michael'
These examples demonstrate the basics of working with CSV and Excel files in Python. You can
expand on these concepts for more advanced use cases, such as handling large datasets,
formatting Excel files, or performing complex data manipulation using pandas.
The os module in Python provides a way to interact with the operating system, perform file and
directory operations, and execute system-level commands. Here are some common operations
and commands you can use with the os module.
import os
# Get current working directory
current_dir = os.getcwd()
print("Current Directory:", current_dir)
import os
# Change to a specific directory
os.chdir('/path/to/directory')
# Verify the current working directory
print("New Directory:", os.getcwd())
import os
# List all files and directories in the current directory
files = os.listdir('.')
print("Files and Directories:", files)
import os
# Create a new directory
os.mkdir('new_folder')
# Verify the directory was created
print("Directory created:", os.path.isdir('new_folder'))
import os
# Remove a directory
os.rmdir('new_folder')
# Verify the directory was removed
print("Directory removed:", not os.path.isdir('new_folder'))
2. File Operations
import os
# Check if a file exists
if os.path.exists('file.txt'):
print("File exists")
else:
print("File does not exist")
Use os.stat(path) to get details like file size, creation time, and last modified time.
import os
# Get file information
file_info = os.stat('file.txt')
# Print file size in bytes
print("File size:", file_info.st_size)
import os
# Rename a file
os.rename('old_file.txt', 'new_file.txt')
2.4. Remove a File
import os
# Remove a file
os.remove('file_to_delete.txt')
import os
# Run a shell command (list files in the current directory)
os.system('ls')
import os
# Execute a command to list files on Windows
os.system('dir') # For Windows
# Execute a command to list files on Linux/macOS
# os.system('ls') # For Linux/macOS
To capture the output of a command, use os.popen() or the subprocess module (for more
advanced use cases).
import os
# Run a command and capture output
output = os.popen('echo Hello, World!').read()
print("Command Output:", output)
4. Working with Environment Variables
import os
# Get an environment variable
path = os.environ.get('PATH')
print("PATH Environment Variable:", path)
import os
# Set an environment variable
os.environ['MY_VAR'] = 'Some Value'
# Access the newly set environment variable
print("MY_VAR:", os.environ.get('MY_VAR'))
import os
# Join paths
full_path = os.path.join('folder', 'subfolder', 'file.txt')
print("Full Path:", full_path)
5.2. Get Absolute Path
import os
# Get absolute path of a file
abs_path = os.path.abspath('file.txt')
print("Absolute Path:", abs_path)
Use os.path.split() to split a path into the directory and the filename.
import os
# Split path into directory and filename
dir_path, file_name = os.path.split('/path/to/file.txt')
print("Directory:", dir_path)
print("File Name:", file_name)
6. Temporary Files
The tempfile module is often used in combination with os to create and manage temporary
files.
import os
import tempfile
# Create a temporary file
with tempfile.TemporaryFile() as temp_file:
temp_file.write(b'Hello, Temporary File!')
temp_file.seek(0)
print(temp_file.read())
7. Process Management
import os
# Get process ID
pid = os.getpid()
print("Process ID:", pid)
import os
# Get parent process ID
ppid = os.getppid()
print("Parent Process ID:", ppid)
8. File Permissions
import os
# Change file permissions (e.g., make a file read-only)
os.chmod('file.txt', 0o444) # Read-only permission
9. Check Disk Usage
import os
# Check disk usage for the current directory
stat = os.statvfs('/')
print("Disk Block Size:", stat.f_frsize)
print("Total Blocks:", stat.f_blocks)
These are just some of the key functionalities provided by the os module for interacting with the
operating system in Python. The os module is extremely versatile and useful for file and
directory management, running shell commands, process management, and more.
The os module and glob module are essential in Python for file management, path operations,
and pattern matching of filenames. Let's explore these modules in more detail.
1. OS Module
The os module provides a way to interact with the operating system. Here are some common
functionalities:
Create a directory:
import os
# Create a new directory
os.mkdir('new_directory')
Remove a directory:
import os
# Remove an empty directory
os.rmdir('new_directory')
import os
# List files and directories in the current directory
files = os.listdir('.')
print(files)
Remove a file:
import os
# Remove a file
os.remove('file_to_delete.txt')
Join paths:
import os
# Join two paths
path = os.path.join('folder', 'subfolder', 'file.txt')
print(path)
Get the absolute path:
import os
# Get absolute path of a file
abs_path = os.path.abspath('file.txt')
print(abs_path)
import os
# Check if the path exists
if os.path.exists('file.txt'):
print("File exists")
else:
print("File does not exist")
import os
# Get the value of an environment variable
path = os.environ.get('PATH')
print(path)
import os
# Set a new environment variable
os.environ['MY_VAR'] = 'Some Value'
print(os.environ.get('MY_VAR'))
2. Glob Module
The glob module finds all the pathnames matching a specified pattern. It is mainly used for
filename pattern matching.
The glob.glob() function returns a list of filenames that match a specified pattern.
import glob
# Get all .txt files in the current directory
txt_files = glob.glob('*.txt')
print(txt_files)
Output:
You can use glob to match files in subdirectories by using the ** pattern.
import glob
# Get all .txt files in the current directory and all its
subdirectories
txt_files = glob.glob('**/*.txt', recursive=True)
print(txt_files)
Output:
['folder/file1.txt', 'folder/subfolder/file2.txt']
import glob
# Match all files that start with 'data' and end with '.csv'
csv_files = glob.glob('data*.csv')
print(csv_files)
Output:
You can combine os and glob to perform more advanced operations like iterating through files
and applying certain actions.
For example, you can use glob to find all files matching a pattern and os.remove() to delete
them.
import os
import glob
# Find all .tmp files in the current directory
tmp_files = glob.glob('*.tmp')
# Delete each .tmp file
for file in tmp_files:
os.remove(file)
print(f"Deleted {file}")
3.2. Using glob to List Files and os.path for More Details
You can use glob to get a list of files and os.path functions (like os.path.getsize())
to retrieve additional information.
import os
import glob
# List all .txt files
txt_files = glob.glob('*.txt')
# Print the size of each .txt file
for file in txt_files:
size = os.path.getsize(file)
print(f"{file}: {size} bytes")
You can use os.access() to check file permissions before performing file operations.
import os
# Check if a file is readable and writable
file_path = 'file.txt'
if os.access(file_path, os.R_OK | os.W_OK):
print(f"{file_path} is readable and writable.")
else:
print(f"{file_path} is not readable or writable.")
You can use glob to find files with specific patterns, such as files modified today or files with
specific extensions.
import glob
import os
import time
# Get all .log files modified today
today = time.time() - 24*60*60 # 24 hours ago
log_files = glob.glob('*.log')
for file in log_files:
if os.path.getmtime(file) > today:
print(f"{file} was modified today")
The os module can be used in combination with tempfile to create and manage temporary
files.
import os
import tempfile
# Create a temporary file
with tempfile.NamedTemporaryFile(delete=False) as tmp_file:
print(f"Temporary file created: {tmp_file.name}")
tmp_file.write(b"Some data")
You can use os.system() to execute shell commands directly from Python.
import os
# Execute a shell command
os.system('echo "Hello, world!"')
However, note that os.system() is basic and does not capture the output. For more advanced
needs, use subprocess.
7. Platform-Specific Operations
The os module provides platform-specific operations. For instance, checking the operating
system:
import os
# Get the platform
print(os.name) # 'posix' for Linux/MacOS, 'nt' for Windows
import os
if os.name == 'nt':
os.system('cls') # Clear the screen for Windows
else:
os.system('clear') # Clear the screen for Linux/MacOS
Summary
● os module: Useful for handling file and directory operations, interacting with
environment variables, running shell commands, and more.
● glob module: Used for matching file patterns using wildcards. It's great for working
with filenames in directories.
● Combining os and glob: You can combine both modules to perform tasks like batch
file deletions, file size calculations, or even iterating over files and directories.
Module 15 - Exceptions
1. Errors in a Python Program
Exception handling in Python allows you to handle runtime errors gracefully instead of letting
the program crash. Python uses try, except, else, and finally blocks to handle
exceptions effectively.
1. Syntax Errors
○ Occur due to incorrect syntax.
○ Example: Missing a colon at the end of a loop.
for i in range(5) # Missing colon
print(i)
Syntax:
try:
# Code that may raise an exception
except ExceptionType:
# Code to handle the exception
else:
# Code to execute if no exception occurs
finally:
# Code to execute regardless of an exception
try:
num = int(input("Enter a number: "))
result = 10 / num
print("Result:", result)
except ValueError:
print("Invalid input! Please enter a number.")
except ZeroDivisionError:
print("Division by zero is not allowed.")
else:
print("Calculation was successful!")
finally:
print("End of program.")
Best Practices
2. Exceptions
Exceptions in Python are errors detected during execution. They disrupt the normal flow of a
program and can be managed using exception handling to avoid crashes and handle errors
gracefully.
Built-in Exceptions
1. ArithmeticError
○ Base class for arithmetic-related errors.
○ Examples: ZeroDivisionError, OverflowError.
2. IndexError
○ Raised when accessing an invalid index of a sequence (e.g., list, string).
3. KeyError
○ Raised when trying to access a non-existent key in a dictionary.
4. ValueError
○ Raised when an operation receives an argument of the correct type but
inappropriate value.
5. TypeError
○ Raised when an operation is applied to an object of inappropriate type.
6. NameError
○ Raised when a variable or name is not defined.
7. FileNotFoundError
○ Raised when a file operation is requested, but the file does not exist.
8. EOFError
○ Raised when the input() function hits end-of-file condition.
9. ImportError
○ Raised when an import statement fails to find the module.
10. RuntimeError
○ Raised when an error does not fall under other specific categories.
You can handle exceptions using try, except, else, and finally blocks.
Structure
try:
# Code that might raise an exception
except ExceptionType:
# Code to handle the exception
else:
# Code to execute if no exception occurs
finally:
# Code to execute no matter what (optional)
Examples
try:
x = int(input("Enter a number: "))
print(10 / x)
except ZeroDivisionError:
print("You cannot divide by zero.")
2. Multiple Exceptions
try:
x = int(input("Enter a number: "))
print(10 / x)
except ZeroDivisionError:
print("Cannot divide by zero!")
except ValueError:
print("Invalid input! Enter a valid number.")
3. Generic Exception
try:
x = int(input("Enter a number: "))
print(10 / x)
except Exception as e:
print(f"An error occurred: {e}")
try:
x = int(input("Enter a number: "))
print(10 / x)
except ZeroDivisionError:
print("Division by zero is not allowed.")
else:
print("Operation successful!")
finally:
print("This block always executes.")
5. Raising Exceptions
x = -1
if x < 0:
raise ValueError("Negative value not allowed!")
6. Custom Exceptions
class NegativeNumberError(Exception):
pass
try:
x = int(input("Enter a positive number: "))
if x < 0:
raise NegativeNumberError("Negative numbers are not
allowed.")
except NegativeNumberError as e:
print(e)
Key Points
3. print("Error:", e)
3. Exception Handling
Exception handling in Python allows programs to deal with runtime errors gracefully, ensuring
the program doesn’t crash unexpectedly and can recover or exit cleanly. It uses a combination of
try, except, else, and finally blocks.
Basic Syntax
try:
# Code that might raise an exception
except ExceptionType:
# Code to handle the exception
else:
# Code to execute if no exception occurs
finally:
# Code to execute no matter what
1. try Block
Contains the code that might raise an exception.
2. except Block
Handles specific or general exceptions. Multiple except blocks can handle different
error types.
3. else Block (Optional)
Executes only if the try block does not raise any exceptions.
4. finally Block (Optional)
Executes regardless of whether an exception was raised or not. Often used for cleanup.
Best Practices
Handle Specific Exceptions
Always catch specific exceptions rather than a generic one, unless necessary.
except ZeroDivisionError:
...
Avoid Bare except:
It catches all exceptions, including unexpected ones like KeyboardInterrupt.
# Avoid this:
except:
print("Something went wrong!")
Use finally for Cleanup
Close files, release resources, or perform any necessary cleanup.
try:
file = open("example.txt", "r")
# Perform operations
finally:
file.close()
Log Exceptions
Use logging to capture errors for debugging instead of printing them.
import logging
try:
...
except Exception as e:
logging.error(f"Error occurred: {e}")
Rethrow Exceptions if Necessary
If you cannot handle the exception fully, re-raise it for higher-level handling.
try:
...
except Exception:
raise
4. Types of Exceptions
Python provides a rich set of built-in exceptions to handle various types of errors. These
exceptions can be categorized based on their functionality and usage.
1. Arithmetic-Related Exceptions
● ArithmeticError
Base class for all arithmetic-related errors.
ZeroDivisionError
Raised when dividing by zero.
print(10 / 0) # ZeroDivisionError
OverflowError
Raised when a calculation exceeds the maximum limit for a numeric type.
import math
print(math.exp(1000)) # OverflowError
● FloatingPointError
Raised when a floating-point operation fails (rare in modern Python).
2. Indexing and Key Errors
IndexError
Raised when accessing an invalid index in a sequence.
my_list = [1, 2, 3]
print(my_list[5]) # IndexError
KeyError
Raised when accessing a non-existent key in a dictionary.
my_dict = {"a": 1}
print(my_dict["b"]) # KeyError
3. Value-Related Exceptions
ValueError
Raised when a function receives an argument of the correct type but inappropriate value.
print(int("abc")) # ValueError
TypeError
Raised when an operation is applied to an object of inappropriate type.
print("5" + 5) # TypeError
4. Input/Output Exceptions
FileNotFoundError
Raised when trying to access a file that does not exist.
open("non_existent_file.txt", "r") # FileNotFoundError
EOFError
Raised when the input() function hits the end of file.
while True:
input() # Press Ctrl+D to raise EOFError
PermissionError
Raised when trying to perform an operation without the necessary permissions.
5. Import Errors
ImportError
Raised when an import statement fails.
import non_existent_module # ImportError
ModuleNotFoundError
A subclass of ImportError, specifically for missing modules.
import nonexistentmodule # ModuleNotFoundError
6. Name-Related Exceptions
NameError
Raised when a variable or function is not defined.
print(undeclared_variable) # NameError
● UnboundLocalError
A subclass of NameError, raised when trying to use a local variable before assigning it.
7. OS-Related Exceptions
● OSError
Base class for errors related to system operations.
FileExistsError
Raised when trying to create a file or directory that already exists.
import os
os.mkdir("existing_dir") # FileExistsError
● IsADirectoryError
Raised when a directory is used in place of a file.
● NotADirectoryError
Raised when a file is used in place of a directory.
8. Attribute and Lookup Errors
AttributeError
Raised when an invalid attribute is accessed.
my_list = [1, 2, 3]
my_list.append(4)
my_list.nonexistent_method() # AttributeError
● LookupError
Base class for errors related to invalid lookups.
○ Subclasses: IndexError, KeyError.
9. Memory-Related Exceptions
● MemoryError
Raised when an operation runs out of memory.
RecursionError
Raised when the maximum recursion depth is exceeded.
def recursive():
recursive()
recursive() # RecursionError
AssertionError
Raised when an assert statement fails.
assert 2 + 2 == 5, "Math is broken!" # AssertionError
● RuntimeError
Generic error when no other specific exception applies.
● NotImplementedError
Raised when a method is not implemented in a subclass.
class CustomError(Exception):
pass
try:
raise CustomError("This is a custom exception!")
except CustomError as e:
print(e)
Hierarchy of Exceptions
All exceptions in Python inherit from the base class BaseException. The hierarchy looks like
this:
BaseException
├── SystemExit
├── KeyboardInterrupt
├── GeneratorExit
└── Exception
├── ArithmeticError
│ ├── ZeroDivisionError
│ ├── OverflowError
│ └── FloatingPointError
├── LookupError
│ ├── IndexError
│ └── KeyError
├── OSError
│ ├── FileNotFoundError
│ ├── PermissionError
│ └── ...
├── ImportError
│ └── ModuleNotFoundError
├── ...
The except block is used in Python to handle exceptions that occur in the try block. It
ensures the program can handle errors gracefully without crashing.
Basic Syntax
try:
# Code that may raise an exception
except ExceptionType:
# Code to handle the exception
finally:
# Code that always executes
Examples
try:
result = 10 / 0
except ZeroDivisionError:
print("Error: Division by zero is not allowed.")
finally:
print("Execution of the `finally` block.")
Output:
try:
num = int(input("Enter a number: "))
print(10 / num)
except ZeroDivisionError:
print("Cannot divide by zero!")
except ValueError:
print("Invalid input! Please enter a number.")
finally:
print("Cleanup or final message.")
Use a generic except block to catch all exceptions. Caution: This should only be used when
you genuinely need to handle all exceptions.
try:
print("Performing operation...")
result = 10 / "five"
except Exception as e:
print(f"An error occurred: {e}")
finally:
print("This block always executes.")
Output:
try:
result = 10 / 2
except ZeroDivisionError:
print("Division by zero is not allowed.")
else:
print(f"The result is: {result}")
finally:
print("Execution complete.")
Output:
The finally block is often used to release resources, such as closing files or database
connections.
try:
file = open("example.txt", "r")
# Perform file operations
except FileNotFoundError:
print("File not found.")
finally:
print("Closing the file.")
if 'file' in locals() and not file.closed:
file.close()
Use Cases
1. Error Handling: Prevent the program from crashing due to unhandled exceptions.
2. Resource Cleanup: Close files, network connections, or release locks.
3. Logging: Log errors or critical messages.
4. Guaranteed Execution: Ensure specific code runs no matter what.
The assert statement is used for debugging purposes. It helps you test assumptions in your
code and raises an AssertionError if the condition provided is False. Assertions are
typically used during development to catch bugs early but are not meant for handling runtime
errors in production.
Syntax
Basic Examples
x = 10
assert x > 5 # Passes because 10 > 5
assert x < 5 # Raises AssertionError
Output:
x = 10
assert x < 5, "x is not less than 5"
Output:
How It Works
Usage Scenarios
1. Debugging
Assertions can help ensure certain conditions hold true while testing.
def factorial(n):
assert n >= 0, "Factorial is not defined for negative
numbers"
if n == 0:
return 1
return n * factorial(n - 1)
print(factorial(5)) # 120
print(factorial(-1)) # Raises AssertionError
3. Ensuring Invariants
x = 10
y = 5
assert x > y, "x should always be greater than y"
Disabling Assertions
Assertions can be disabled globally when running Python in optimized mode (using the -O flag).
Example
python -O script.py
● This ignores all assert statements in the code, making it suitable for production where
assertions are unnecessary.
Key Points
1. Not for Error Handling: Assertions are for catching bugs during development, not for
handling user input or runtime errors.
○ Use exceptions like ValueError or TypeError for user-facing error
handling.
2. Performance Impact: Assertions are removed in optimized mode, so they should not be
relied upon for critical functionality.
3. Custom AssertionError Messages: Always include meaningful messages to make
debugging easier.
Best Practices
1. Use assert for conditions that should never fail in a correctly functioning program.
2. Avoid using assert for validating external inputs (like user input or file data).
3. Remove or disable assertions in production for better performance.
7. User-Defined Exceptions
In Python, you can create your own exceptions by subclassing the built-in Exception class (or
any of its subclasses). This is useful when you want to define application-specific error handling.
Basic Syntax
class CustomException(Exception):
pass
Examples
class CustomError(Exception):
pass
try:
raise CustomError("This is a custom exception.")
except CustomError as e:
print(e)
Output:
class InsufficientFundsError(Exception):
def __init__(self, balance, amount):
self.balance = balance
self.amount = amount
super().__init__(f"Insufficient funds: Balance =
{balance}, Amount = {amount}")
# Example Usage
try:
balance = 100
withdraw_amount = 200
if withdraw_amount > balance:
raise InsufficientFundsError(balance, withdraw_amount)
except InsufficientFundsError as e:
print(e)
Output:
class InvalidAgeError(Exception):
def __init__(self, age):
self.age = age
def age_message(self):
return f"Invalid age: {self.age}. Age must be between 0
and 120."
# Example Usage
try:
age = -5
if age < 0 or age > 120:
raise InvalidAgeError(age)
except InvalidAgeError as e:
print(e.age_message())
Output:
You can define a base exception class and create multiple subclasses for specific types of errors.
class ApplicationError(Exception):
"""Base class for all application-related errors."""
pass
class DatabaseError(ApplicationError):
"""Exception raised for database-related errors."""
pass
class ValidationError(ApplicationError):
"""Exception raised for validation-related errors."""
pass
# Example Usage
try:
raise DatabaseError("Database connection failed.")
except DatabaseError as e:
print(f"Database Error: {e}")
except ValidationError as e:
print(f"Validation Error: {e}")
Output:
Best Practices
EXAMPLE
Core Classes:
User-Defined Exceptions:
Built-In Exceptions:
Flow:
Static Methods:
● For utility tasks, such as checking the total number of books in the library.
Encapsulation:
● Use private attributes for sensitive data.
● Provide controlled access using properties.
Properties:
# User-Defined Exceptions
class BookNotAvailableError(Exception):
class UserNotRegisteredError(Exception):
class OverdueLimitError(Exception):
self.title = title
self.author = author
@property
def is_borrowed(self):
return self._is_borrowed
@is_borrowed.setter
self._is_borrowed = value
def __str__(self):
class User:
def __init__(self, name):
self.name = name
@property
def borrowed_books(self):
return self._borrowed_books
@property
def overdue_books(self):
return self._overdue_books
@overdue_books.setter
if value < 0:
self._overdue_books = value
raise BookNotAvailableError(book.title)
self._borrowed_books.append(book)
book.is_borrowed = True
if book in self._borrowed_books:
self._borrowed_books.remove(book)
book.is_borrowed = False
def __str__(self):
class Library:
def __init__(self):
@staticmethod
def total_books(library):
return len(library._books)
def add_book(self, book):
self._books[book.title] = book
self._users[user.name] = user
raise UserNotRegisteredError(user_name)
user = self._users[user_name]
book = self._books[book_title]
if user.overdue_books > 3:
raise OverdueLimitError(user_name,
user.overdue_books)
# Borrow the book
user.borrow_book(book)
raise UserNotRegisteredError(user_name)
user = self._users[user_name]
book = self._books[book_title]
user.return_book(book)
# Example Usage
try:
library = Library()
# Register users
library.register_user(User("Alice"))
library.register_user(User("Bob"))
# Borrow books
library.borrow_book("Alice", "1984")
library.borrow_book("Alice", "1984")
except BookNotAvailableError as e:
print(e)
except UserNotRegisteredError as e:
print(e)
except OverdueLimitError as e:
print(e)
except KeyError as e:
print(f"Error: {e}")
except ValueError as e:
print(f"ValueError: {e}")
except Exception as e:
finally:
Sample Output
Total books in the library: 3
Here's an example demonstrating how to open, read, write, and close a file in Python:
# Writing to a file
file_path = "example.txt"
# Appending to a file
# Open the file in append mode
with open(file_path, "a") as file:
file.write("\nThis is an additional line appended to the
file.")
print("\nNew data appended successfully.")
Explanation:
1. Writing (w mode):
○ Opens the file for writing. Creates the file if it doesn't exist, or truncates the file if
it does.
○ Use file.write() to write data to the file.
2. Reading (r mode):
○ Opens the file for reading. Throws an error if the file does not exist.
○ Use file.read() to read the entire file content.
3. Appending (a mode):
○ Opens the file for appending. Creates the file if it doesn't exist.
○ Adds data to the end of the file without overwriting the existing content.
4. Automatic File Closing:
○ Using the with open(...) construct ensures that the file is properly closed
after the block is executed, even if an error occurs.
Output:
Python provides a convenient tempfile module to create temporary files. These files are
useful for storing data temporarily and are automatically deleted when closed or when the
program exits. Here's how you can create and work with temporary files:
import tempfile
Explanation:
1. tempfile.NamedTemporaryFile:
○ Creates a temporary file with a unique name.
○ You can use mode='w+' for read/write access.
○ The delete=False parameter ensures the file persists after closing, so it can
be manually deleted later.
2. Attributes:
○ temp_file.name: Provides the full path to the temporary file.
3. Automatic Cleanup:
○ If delete=True (default), the temporary file is automatically deleted when the
file is closed.
Example Output:
# The directory and its contents are deleted when the block
ends.
This ensures you can safely handle temporary data without manually cleaning up.
Working with text files containing strings is a common task in Python. Here’s a breakdown of
how to handle reading, writing, appending, and searching strings in a text file:
file_name = "example.txt"
# Open the file in write mode
with open(file_name, "w") as file:
file.write("Hello, World!\n")
file.write("Python makes file handling easy.\n")
file.write("This file contains strings for testing
purposes.\n")
search_term = "Python"
# Open the file in read mode
with open(file_name, "r") as file:
lines = file.readlines()
target_word = "file"
count = 0
old_string = "file"
new_string = "document"
Sample Output
To check if a file exists in Python, you can use the os.path module or the pathlib module.
Both methods are straightforward and effective. Here are examples:
Using os.path
import os
file_name = "example.txt"
Using pathlib
file_path = Path("example.txt")
# Check if the file exists
if file_path.exists():
print(f"The file '{file_path}' exists.")
else:
print(f"The file '{file_path}' does not exist.")
Additional Checks
if not file_path.exists():
with open(file_name, "w") as file:
file.write("This is a newly created file.")
print(f"File '{file_name}' created successfully.")
else:
print(f"File '{file_name}' already exists.")
Output
This approach ensures that you can manage file existence efficiently before performing
operations like reading, writing, or deleting.
Working with binary files in Python involves handling files that contain non-text data, such as
images, audio files, or executable files. Python allows you to read and write binary data using rb
(read binary) and wb (write binary) modes.
To write binary data, you can use the wb mode. You can write bytes or byte arrays into the file.
To read binary data, you use the rb mode, and you can read the data as bytes.
Let's say you want to copy an image file as a binary file. You can read the image file and write it
to a new file in binary mode:
# Open the source image in read binary mode and the destination
in write binary mode
with open(source_image, "rb") as source_file:
image_data = source_file.read()
# Create a bytearray
binary_array = bytearray([1, 2, 3, 4, 5])
If you need to read large binary files, you can read them in chunks:
This method is useful for processing large files without loading the entire file into memory.
To verify if the file is binary or text, you can inspect the data for special characters, but generally,
if you open a file in binary mode (rb or wb), you are working with binary data.
Summary of Modes:
This approach allows you to handle binary data effectively, making it easy to read and write files
that contain non-text content.
The with statement in Python is used for simplifying the management of resources like file
handling, database connections, and network connections. It ensures that resources are properly
acquired and released, even if an exception occurs during the execution of the block.
Basic Syntax
1. File Handling
When working with files, the with statement ensures that the file is automatically closed after it
is no longer needed, even if an error occurs during file operations.
# Writing to a file
with open('example.txt', 'w') as file:
file.write('Hello, World!\n')
file.write('Python with statement makes resource management
easy.')
In this example:
The with statement is equally useful for reading files, ensuring they are closed after reading,
even if an exception occurs during reading.
You can create your own context managers using the contextlib module or by defining a
class with __enter__() and __exit__() methods.
@contextmanager
def sample_resource():
print("Resource acquired")
yield
print("Resource released")
Resource acquired
Inside the context block.
Resource released
In this example:
4. Database Connections
The with statement is frequently used to manage database connections, ensuring that the
connection is closed after the operations are complete, even in the case of an error.
import sqlite3
The connection is automatically committed and closed when the block exits.
How with Works:
The with statement works with context managers. A context manager defines two methods:
1. __enter__(): This method is executed when entering the with block. It acquires the
resource and optionally returns it (e.g., the file object).
2. __exit__(): This method is executed when exiting the with block, even if an
exception occurs. It handles the cleanup, such as closing the file or releasing the resource.
class MyContextManager:
def __enter__(self):
print("Entering the context")
return self # Resource can be returned here
Output:
If an exception occurs in the with block, the __exit__() method can handle the exception.
class MyContextManager:
def __enter__(self):
print("Entering the context")
return self
Output:
Summary of Benefits
● Automatic Cleanup: You don't need to explicitly close resources (files, connections,
etc.).
● Exception Safety: Resources are properly released, even if an error occurs.
● Cleaner Code: The code is more concise and easier to read.
By using the with statement, Python code becomes more robust and resource-efficient.
7. Pickle in Python
Pickle is a module in Python used to serialize and deserialize Python objects into a byte stream
(binary format). Serialization (also called "pickling") refers to converting a Python object into a
byte stream so that it can be saved to a file, sent over a network, or stored in a database.
Deserialization (also called "unpickling") refers to reconstructing the Python object from the byte
stream.
Here’s a simple example of how to use pickle for serializing and deserializing Python objects.
import pickle
# Data to pickle
data = {'name': 'Alice', 'age': 30, 'city': 'Wonderland'}
In this example:
● pickle.load(file) reads the binary data from the file and deserializes it back into
a Python object.
Pickle can handle more complex objects like classes, lists, tuples, and dictionaries. Here’s an
example with a custom class:
import pickle
def __repr__(self):
return f"Person(name={self.name}, age={self.age})"
In this example:
● The Person class is pickled and unpickled just like any other object. It will retain its
structure and values when loaded back.
You can also pickle and unpickle objects to and from memory (in a string or bytes), without
needing to use files.
Pickling to Memory (dumps()):
In this case:
4. Pickle Protocols
Pickle supports multiple protocols for serialization. Each protocol has different features and
levels of efficiency.
● Protocol 0: ASCII (text) format. It is the oldest and backward-compatible but not as
efficient.
● Protocol 1: Binary format, introduced in Python 2.
● Protocol 2: More efficient binary format.
● Protocol 3: Introduced in Python 3. It is compatible with Python 3.x but not Python 2.x.
● Protocol 4: Introduced in Python 3.4, it supports more data types and is even more
efficient.
● Protocol 5: Introduced in Python 3.8, which adds support for efficient out-of-band data
and other features.
5. Security Warning
Pickle can execute arbitrary code during unpickling, which could be a security risk if the pickle
data is received from an untrusted source. Never unpickle data from an untrusted or
unauthenticated source as it can lead to code execution vulnerabilities.
To safely handle data, consider alternatives like JSON for simpler, non-executable data.
import pickle
While pickle is great for serializing Python objects, consider these alternatives based on use
case:
JSON: Best for exchanging data between systems or when interoperability with other
programming languages is required. It supports basic data types like strings, numbers, lists, and
dictionaries.
import json
data = {'name': 'Alice', 'age': 30}
with open('data.json', 'w') as file:
json.dump(data, file)
shelve: A persistent dictionary that stores Python objects in a file with a simple key-value
interface.
import shelve
with shelve.open('my_shelf') as shelf:
shelf['person'] = person
Summary
● Pickle is used to serialize and deserialize Python objects, making it easy to store and
retrieve complex data structures.
● It can be used with both simple and custom objects.
● Pickle is efficient but should be used cautiously, especially when unpickling data from
untrusted sources.
● Other serialization options like JSON or shelve might be better suited for certain tasks,
especially when dealing with cross-platform or cross-language data exchanges.
8. The seek() and tell() Methods
The seek() and tell() methods in Python are used to manipulate and track the position of
the file pointer in a file. These methods are typically used when working with files in binary
mode or when you need to manage the reading/writing positions in the file manually.
1. seek() Method
The seek() method is used to change the file pointer's position to a specific location within the
file. This is especially useful when you're reading or writing to a specific part of a file without
having to read through the entire file sequentially.
Syntax:
file.seek(offset, whence)
● offset: The number of bytes to move the file pointer. It can be positive (to move
forward) or negative (to move backward).
● whence: (Optional) Specifies from where to start counting the offset. The default
value is os.SEEK_SET (start of the file).
○ os.SEEK_SET: The offset is relative to the beginning of the file (default).
○ os.SEEK_CUR: The offset is relative to the current file position.
○ os.SEEK_END: The offset is relative to the end of the file.
Example of seek():
In this example:
● file.seek(10) moves the file pointer to the 10th byte from the beginning of the file.
● file.seek(-5, 1) moves the pointer 5 bytes backward from the current position.
● file.seek(0, 2) moves the pointer to the end of the file.
2. tell() Method
The tell() method is used to return the current position of the file pointer. This is useful to
know where the pointer is after reading or writing data, especially when working with large files
or when you want to resume reading from a specific location.
Syntax:
file.tell()
● It returns the current position of the file pointer in terms of the number of bytes from the
beginning of the file.
Example of tell():
In this example:
Here’s a practical example where seek() and tell() are used together to navigate through a
file:
When working with binary files, seek() and tell() become more essential, as the position
of the file pointer matters in terms of byte offsets rather than line numbers or character positions.
In this case:
● seek(offset, whence): Moves the file pointer to a specific position in the file.
The position is determined based on offset and the whence parameter.
● tell(): Returns the current position of the file pointer.
These methods are essential for file navigation, allowing you to move to specific positions within
the file, read or write data from a particular point, and track the pointer's location within the file.
CSV (Comma-Separated Values) files are commonly used for storing tabular data, and Python
provides several ways to work with CSV files. The csv module is built into Python for reading
and writing CSV files, and you can also use pandas for more advanced operations.
The csv module allows you to easily read and write CSV files.
To read a CSV file, you can use the csv.reader function. Here's an example:
import csv
You can write data to a CSV file using the csv.writer function:
import csv
You can also use csv.DictReader and csv.DictWriter to work with CSV files in a
dictionary format:
import csv
# Reading a CSV file using DictReader
with open('data.csv', mode='r') as file:
reader = csv.DictReader(file)
In this example, the keys of the dictionary correspond to the column names in the CSV file.
To work with Excel files, you can use the openpyxl module for .xlsx files or the pandas
library, which provides a high-level API for both .xlsx and .csv files.
The openpyxl library is used for reading and writing .xlsx files. First, install openpyxl:
pandas provides a convenient API for working with both CSV and Excel files. To work with
Excel files, you need to install the openpyxl or xlrd library (for older .xls files):
import pandas as pd
import pandas as pd
# Create a DataFrame
df = pd.DataFrame(data)
You can read and write to multiple sheets within an Excel file:
1. CSV Files:
○ Use the csv module to read and write CSV files.
○ You can use csv.reader and csv.writer for simple operations, or
csv.DictReader and csv.DictWriter for working with data in
dictionary format.
2. Excel Files:
○ Use openpyxl for reading and writing .xlsx files, or pandas for a
higher-level approach that supports both .xlsx and .csv files.
○ pandas provides efficient methods for working with tabular data, and it supports
reading and writing to multiple sheets in an Excel file.
Both csv and pandas are commonly used for data processing, and openpyxl is useful when
working with Excel files when more control over formatting is needed.
Working with images in Python is often done using libraries like Pillow (PIL Fork), which
provides a simple and powerful way to open, manipulate, and save image files in various
formats.
1. Installing Pillow
First, you'll need to install the Pillow library if you haven't already:
You can open and display an image using the Pillow library. Here's how:
Once you've modified an image, you can save it in various formats like PNG, JPEG, etc.
You can retrieve the dimensions of an image (width and height) using the size attribute:
5. Resizing Images
● resize((400, 400)): Resizes the image to a width and height of 400x400 pixels.
6. Cropping Images
To crop an image, you specify a box with the coordinates (left, upper, right,
lower):
You can rotate and flip images using the rotate() and transpose() methods:
Rotating:
Flipping (Transpose):
The ImageFilter module provides several image filters such as blur, sharpen, and more.
Other Filters:
You can use the ImageDraw module to draw shapes, text, etc., on an image.
If you're working with images that have transparency (e.g., PNG), you can manipulate the alpha
channel (transparency) as well:
# Convert to grayscale
image = image.convert('L')
These are just a few of the basic operations you can perform with images using Python. The
Pillow library is very powerful and allows for more complex image processing tasks,
including advanced filters, transformations, and effects.
Working with directories in Python can be done using the built-in os and pathlib modules.
Both modules provide functions for creating, navigating, and managing directories.
The os module provides a set of methods to interact with the file system, including functions for
working with directories.
Creating a Directory
You can create a directory using os.mkdir() for a single directory or os.makedirs() for
creating intermediate directories as well.
import os
You can list the files and subdirectories inside a directory using os.listdir():
import os
● os.listdir() returns a list of the names of the entries in the directory given by the
path.
import os
# Check if it is a directory
if os.path.isdir('new_directory'):
print('It is a directory')
Removing a Directory
import os
pathlib provides an object-oriented approach to handle file system paths and directories.
Creating a Directory
# Creating a directory
path = Path('new_directory')
path.mkdir(parents=True, exist_ok=True)
You can list the files and directories inside a directory using Path.iterdir():
# Check if it is a directory
if path.is_dir():
print('It is a directory')
You can change the current working directory using os.chdir() (as there’s no direct method
in pathlib):
Removing a Directory
import os
from pathlib import Path
Both the os and pathlib modules provide ways to interact with the file system, with
pathlib offering a more modern and object-oriented approach. For newer codebases, it's
recommended to use pathlib for its cleaner syntax and better integration with other Python
libraries.
1. Character Classes
Define a set of characters that a single position in the string can match:
○ [abc]: Matches a, b, or c.
○ [a-z]: Matches any lowercase letter.
○ [0-9]: Matches any digit.
pattern = r"[a-z][0-9]"
2. Quantifiers
Match sequences of characters with specific lengths:
○ *: Matches 0 or more occurrences.
○ +: Matches 1 or more occurrences.
○ ?: Matches 0 or 1 occurrence.
○ {n}: Matches exactly n occurrences.
○ {n,}: Matches n or more occurrences.
○ {n,m}: Matches between n and m occurrences.
pattern = r"\d{3}-\d{2}-\d{4}"
match = re.search(pattern, "123-45-6789")
if match:
print("Match found!")
3. Escape Sequences
Special sequences to match predefined sets:
○ \d: Matches a digit ([0-9]).
○ \D: Matches a non-digit.
○ \w: Matches an alphanumeric character ([a-zA-Z0-9_]).
○ \W: Matches a non-alphanumeric character.
○ \s: Matches a whitespace character.
○ \S: Matches a non-whitespace character.
pattern = r"\w+\s\w+"
match = re.search(pattern, "hello world")
if match:
print("Match found!")
Example:
import re
Quantifiers in regular expressions (regex) define how many times a specific pattern must occur
for it to match. Here's an overview of the quantifiers available in Python's re module:
Common Quantifiers
1. * (Zero or more)
○ Matches 0 or more occurrences of the preceding pattern.
import re
pattern = r"ab*"
match = re.search(pattern, "a") # Matches "a"
match = re.search(pattern, "abbb") # Matches "abbb"
2. + (One or more)
○ Matches 1 or more occurrences of the preceding pattern.
pattern = r"ab+"
match = re.search(pattern, "ab") # Matches "ab"
match = re.search(pattern, "abbb") # Matches "abbb"
match = re.search(pattern, "a") # No match
3. ? (Zero or one)
○ Matches 0 or 1 occurrence of the preceding pattern.
pattern = r"ab?"
match = re.search(pattern, "a") # Matches "a"
match = re.search(pattern, "ab") # Matches "ab"
match = re.search(pattern, "abb") # Matches "ab"
pattern = r"a{3}"
match = re.search(pattern, "aaa") # Matches "aaa"
match = re.search(pattern, "aa") # No match
5. {n,} (At least n occurrences)
○ Matches n or more occurrences of the preceding pattern.
pattern = r"a{2,}"
match = re.search(pattern, "aaa") # Matches "aaa"
match = re.search(pattern, "aa") # Matches "aa"
match = re.search(pattern, "a") # No match
pattern = r"a{2,4}"
match = re.search(pattern, "aa") # Matches "aa"
match = re.search(pattern, "aaa") # Matches "aaa"
match = re.search(pattern, "aaaa") # Matches "aaaa"
match = re.search(pattern, "aaaaa") # Matches "aaaa"
Quantifiers are greedy by default, meaning they match as many occurrences as possible. To make
them non-greedy, append a ? after the quantifier.
Greedy Example:
pattern = r"a.*b"
text = "acbacb"
match = re.search(pattern, text) # Matches "acbacb"
Non-Greedy Example:
pattern = r"a.*?b"
text = "acbacb"
match = re.search(pattern, text) # Matches "acb"
Practical Examples
Matching Phone Numbers
pattern = r"\d{3}-\d{3}-\d{4}"
match = re.search(pattern, "123-456-7890")
if match:
print("Valid phone number!")
Extracting Words with Optional Suffix
pattern = r"\bcat(s)?\b"
text = "I have a cat and two cats."
matches = re.findall(pattern, text)
print(matches) # Matches "cat" and "cats"
Validating Password Length
pattern = r".{8,}"
match = re.search(pattern, "securePass")
if match:
print("Valid password!")
The re module in Python provides several methods to work with regular expressions. Here's an
overview of the commonly used methods:
1. findall()
● Purpose: Returns a list of all non-overlapping matches of the pattern in the string.
● Usage: Ideal for extracting multiple occurrences of a pattern.
Syntax:
re.findall(pattern, string, flags=0)
Example:
import re
text = "The price is $5, and the discount is $2."
pattern = r"\$\d+"
matches = re.findall(pattern, text)
print(matches) # Output: ['$5', '$2']
2. finditer()
● Purpose: Returns an iterator yielding match objects for all non-overlapping matches in
the string.
● Usage: Useful when you need detailed match information (like start and end positions).
Syntax:
re.finditer(pattern, string, flags=0)
Example:
import re
text = "The price is $5, and the discount is $2."
pattern = r"\$\d+"
matches = re.finditer(pattern, text)
for match in matches:
print(f"Match: {match.group()}, Start: {match.start()}, End:
{match.end()}")
# Output:
# Match: $5, Start: 13, End: 15
# Match: $2, Start: 35, End: 37
3. search()
● Purpose: Searches the string for the first occurrence of the pattern and returns a match
object if found.
● Usage: Best when you want to find the first match or verify if a pattern exists.
Syntax:
re.search(pattern, string, flags=0)
Example:
import re
text = "Order ID: 12345"
pattern = r"\d+"
match = re.search(pattern, text)
if match:
print(f"Match: {match.group()}, Start: {match.start()}, End:
{match.end()}")
# Output: Match: 12345, Start: 10, End: 15
4. sub()
● Purpose: Replaces all matches of the pattern with a specified replacement string.
● Usage: Useful for substitutions like masking sensitive information or formatting strings.
Syntax:
re.sub(pattern, replacement, string, count=0, flags=0)
Example:
import re
text = "My phone number is 123-456-7890."
pattern = r"\d{3}-\d{3}-\d{4}"
masked = re.sub(pattern, "[REDACTED]", text)
print(masked) # Output: My phone number is [REDACTED].
5. compile()
● Purpose: Compiles a regex pattern into a regex object for repeated use, improving
performance.
● Usage: Use when the same pattern will be applied multiple times.
Syntax:
regex = re.compile(pattern, flags=0)
Example:
import re
pattern = re.compile(r"\d{3}-\d{3}-\d{4}")
text1 = "My phone number is 123-456-7890."
text2 = "Emergency contact: 987-654-3210."
# Use the compiled pattern
print(pattern.search(text1).group()) # Output: 123-456-7890
print(pattern.search(text2).group()) # Output: 987-654-3210
Comparison of Methods
import re
text = "Emails: [email protected], [email protected]"
# Compile a pattern
email_pattern =
re.compile(r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}")
# Mask emails
masked_text = email_pattern.sub("[EMAIL]", text)
print("Masked Text:", masked_text)
Output:
Special characters in regular expressions have specific meanings and allow you to build complex
patterns. Here's a breakdown of these characters and their purposes:
1. Special Characters
. Matches any single character a.c matches abc, a1c, a-c, but not ac.
except a newline (\n).
^ Matches the start of a string. ^hello matches hello world but not world
hello.
$ Matches the end of a string. world$ matches hello world but not world
hello.
{n} Matches exactly n occurrences a{3} matches aaa but not aa or aaaa.
of the preceding character or
group.
2. Special Sequences
\s Matches any whitespace character (spaces, tabs, \s+ matches spaces or other
newlines). whitespace.
When you want to match a literal special character (e.g., *, +, .), you must escape it using \.
Example:
import re
text = "3+5=8"
pattern = r"\+"
match = re.search(pattern, text)
if match:
print("Matched a literal +")
4. Practical Examples
import re
pattern = r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}"
email = "[email protected]"
if re.match(pattern, email):
print("Valid email!")
Extract Digits from a String
import re
text = "Order ID: 12345"
pattern = r"\d+"
numbers = re.findall(pattern, text)
print(numbers) # Output: ['12345']
Match a URL
import re
pattern = r"https?://[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}"
url = "Visit https://example.com for details."
match = re.search(pattern, url)
if match:
print("Found URL:", match.group())
import re
text = "Hello, @world! #Python is amazing."
pattern = r"[^\w\s]"
cleaned = re.sub(pattern, "", text)
print(cleaned) # Output: Hello world Python is amazing
import re
text = "Price is $5.00."
escaped = re.escape(text)
print(escaped) # Output: Price\ is\ \$5\.00\.
Using regular expressions to process files in Python is a common and powerful technique for
tasks like extracting data, validating content, or performing substitutions. Below are key steps
and examples for applying regular expressions to files.
Examples
import re
print("Extracted Emails:")
print(emails)
import re
Suppose a file contains dates in the format MM/DD/YYYY, and you want to change them to
YYYY-MM-DD.
import re
import re
import re
print("Prices found:")
for match in matches:
print(f"Price: {match.group()}, Start: {match.start()}, End:
{match.end()}")
6. Extract Data from a Log File
import re
print("Extracted IP Addresses:")
print(ips)
Best Practices
These examples should cover a wide range of real-world scenarios for using regular expressions
with files in Python!