LECTURE 7
🔹 Exception Handling in Python
Exception handling in Python is the mechanism that allows a program to deal
with unexpected problems during execution. In real-world applications, errors
are normal — users may enter invalid input, files may not exist, network
connections may break, and so on. Instead of letting the program crash,
Python gives us tools to detect, manage, and recover from errors gracefully.
Error-handling ensures:
The program does not stop suddenly
Users receive meaningful feedback
System resources like files and network connections are safely closed
The program can continue running even after something goes wrong
Exception handling makes software more robust, reliable, and safe.
🔹 What Is an Exception?
An exception is an event that interrupts the normal flow of a program. It
occurs when Python encounters a situation it cannot handle automatically.
Examples of situations that cause exceptions:
Dividing a number by zero
Converting invalid text to integer
Accessing invalid list index
Opening a file that does not exist
Providing the wrong type of input
Whenever these events occur, Python generates an Exception Object,
which contains information about the error.
✔ Example — Program Crash Without Exception Handling
🔹 Why Do We Need Exception Handling?
Exception handling is essential because:
1. Programs Should Not Crash
Applications in real life (ATMs, banking software, online stores, games) must
continue running even when something goes wrong.
2. To Provide User-Friendly Messages
3. To Protect Data
Exception handling prevents data corruption during file writing, database
updates, or network transfers.
4. To Ensure Resources Are Released
Files, networks, and memory must be closed or freed properly even if an
error happens.
5. To Make Debugging Easier
Python can tell you exactly what went wrong and where.
🔹 How Python Handles Errors Internally
When an error is detected, Python performs the following steps:
1. Stops executing current instructions
2. Creates an Exception Object
3. Looks for a matching except block
4. If not found → program terminates and prints traceback
This process shows why try–except blocks are necessary.
🔹 The try–except Structure
The basic method for handling exceptions is the try–except block.
This prevents the program from crashing.
🔹 Handling Specific Exceptions
Catching all exceptions with a single except: block is possible, but it is not
considered good practice.
It hides real issues.
Instead, we catch specific exceptions.
✔ Example
try:
value = int(input("Enter a number: "))
except ValueError:
print("Please enter valid digits!")
Why this is better:
Provides accurate error messages
Makes debugging easier
Keeps program behavior predictable
🔹 Multiple except Blocks
A single block of code can produce different kinds of errors.
We can handle them separately:
✔ Example
try:
x = int(input("Enter number: "))
y = int(input("Enter divisor: "))
print(x / y)
except ValueError:
print("Only numbers are allowed.")
except ZeroDivisionError:
print("Division by zero is not allowed.")
This is used heavily in professional software.
🔹 Using one except block for multiple exceptions
Python allows grouping exceptions using parentheses:
✔ Example
try:
number = int("abc")
except (ValueError, TypeError):
print("Invalid input type or value.")
🔹 The else Block
The else block runs only if no exception occurs.
This is useful when you want some code to execute only when everything is
successful.
✔ Example
try:
n = int(input("Enter age: "))
except ValueError:
print("Please enter a valid number.")
else:
print("You entered:", n)
🔹 The finally Block
The finally block always runs — with or without an exception.
It is used for cleanup operations:
Closing files
Closing network connections
Releasing system resources
Resetting states
✔ Example
try:
f = open("[Link]")
except FileNotFoundError:
print("File not found.")
finally:
print("Execution complete.")
🔹 Full try–except–else–finally Structure
This is the most robust format used in real applications.
✔ Example
try:
file = open("[Link]", "r")
content = [Link]()
except FileNotFoundError:
print("The file does not exist.")
else:
print("File read successfully!")
print(content)
finally:
print("Closing program.")
The flow is:
try → risky work
except → handle error
else → only on success
finally → executes always
🔹 How This Connects to Next Topic
We now understand:
How exceptions occur
How they are handled
How to use try, except, else, and finally
Why exception handling is critical
Now we can move smoothly into the next major part:
👉 Built-In Exceptions
Where we study the actual error types available in Python, such as:
ValueError
TypeError
IndexError
ZeroDivisionError
FileNotFoundError
and many more
These exceptions will help us write more accurate and controlled error
handling.
🔷 Built-in Exceptions in Python
Now that we understand what exceptions are and how Python handles them,
the next step is to explore the built-in exceptions Python provides. These
exceptions represent common error situations that occur during program
execution.
Python automatically raises these exceptions when something goes wrong,
and we can catch them using except blocks.
Built-in exceptions make debugging easier because:
They describe the error clearly
They indicate exactly what went wrong
They allow us to write more specific error-handling code
They prevent us from catching unnecessary or unrelated errors
Built-in exceptions are defined inside Python’s standard library and inherit
from the base class Exception.
🔹 Categories of Built-in Exceptions
Python’s built-in exceptions span multiple types of problems:
Arithmetic errors (ZeroDivisionError, OverflowError)
Type and value errors (TypeError, ValueError)
Input/output errors (FileNotFoundError, PermissionError)
Lookup errors (IndexError, KeyError)
Import errors (ImportError, ModuleNotFoundError)
Syntax and indentation errors (SyntaxError, IndentationError)
Attribute and name errors (AttributeError, NameError)
Let’s go through each important one with explanations and examples.
🔷 1. Zero Division Error
Occurs when a number is divided by zero — mathematically impossible and
undefined.
✔ Explanation
Python immediately raises this error if you try to divide by zero during
runtime.
✔ Example
try:
result = 10 / 0
except ZeroDivisionError:
print("You cannot divide by zero.")
🔷 2. Value Error
Occurs when a function receives a valid type but an invalid value.
✔ Explanation
Means:
“You passed me the right kind of data, but the data itself is wrong.”
✔ Example
try:
num = int("hello")
except ValueError:
print("Cannot convert text to an integer.")
🔷 3. Type Error
Occurs when an operation is applied to an object of an inappropriate type.
✔ Example
try:
print("Age: " + 25)
except TypeError:
print("Cannot add a string and integer.")
🔷 4. Name Error
Raised when you try to use a variable that has not been defined.
✔ Example
try:
print(age)
except NameError:
print("Variable is not defined.")
🔷 5. Index Error
Occurs when accessing an index that does not exist in a list.
✔ Example
try:
items = [1, 2, 3]
print(items[5])
except IndexError:
print("List index out of range.")
🔷 6. Key Error
Occurs when accessing a dictionary key that is not present.
✔ Example
try:
data = {"name": "John"}
print(data["age"])
except KeyError:
print("Key does not exist in the dictionary.")
🔷 7. File Not Found Error
Raised when a requested file is missing.
✔ Example
try:
f = open("[Link]")
except FileNotFoundError:
print("File not found on system.")
🔷 8. Permission Error
Occurs when you try to access a file or directory without proper permission.
✔ Example
try:
f = open("/system/[Link]", "w")
except PermissionError:
print("You do not have permission to write this file.")
🔷 9. Attribute Error
Occurs when an attribute or method does not exist for an object.
✔ Example
try:
x = "hello"
[Link]("!")
except AttributeError:
print("String objects have no append() method.")
🔷 10. Import Error / Module Not Found Error
Occurs when Python cannot find the module you are trying to import.
✔ Example
try:
import nonexistent
except ModuleNotFoundError:
print("Module does not exist.")
🔷 11. Syntax Error
Occurs when Python detects incorrect code structure.
This is a compile-time error, not runtime.
✔ Example
try:
eval("if True print('hi')")
except SyntaxError:
print("Syntax is incorrect.")
🔷 12. Indentation Error
Occurs when code indentation is incorrect — Python requires strict
indentation.
✔ Example
code = """
def test():
print('Hello')
"""
try:
exec(code)
except IndentationError:
print("Code indentation is incorrect.")
🔷 13. Overflow Error
Occurs when the result of an arithmetic operation is too large to handle.
✔ Example
try:
import math
[Link](1000)
except OverflowError:
print("Number too large to calculate.")
🔷 14. Runtime Error
Raised when an error cannot fit into any other category.
✔ Example
try:
raise RuntimeError("Something went wrong")
except RuntimeError as e:
print(e)
🔷 15. Stop Iteration Error
Occurs when no more items are available in an iterator.
✔ Example
try:
it = iter([1, 2])
print(next(it))
print(next(it))
print(next(it))
except StopIteration:
print("No more items in iterator.")
🔷 Connecting to Next Topic
Now we understand built-in exceptions, which Python automatically provides.
But what if:
You are building a banking system and want to raise
InvalidBalanceError
You are creating a login system and want to raise
PasswordTooShortError
You are developing a game and want to raise OutOfEnergyError
For such custom situations, Python allows you to create your own
exceptions.
🔷 User-Defined Exceptions
Built-in exceptions are useful for common problems, but many programs
need to handle application-specific errors. These are errors that Python
cannot predict because they are unique to your program’s logic.
For example:
A banking app may need InsufficientBalanceError
A school system may need InvalidGradeError
A hotel reservation system may need RoomNotAvailableError
A login system may need WeakPasswordError
When such situations occur, we raise custom exceptions that describe the
problem more accurately than generic built-in exceptions.
User-defined exceptions make code more readable, maintainable, and
professional.
🔹 Why Do We Need User-Defined Exceptions?
Built-in exceptions like ValueError or TypeError do not always convey the
exact meaning of your problem.
Consider this example:
A user tries to withdraw more money than available in their bank
account
Python will NOT raise any built-in exception (because mathematically
subtraction is valid)
But logically, this is an error.
This requires a custom exception such as:
InsufficientBalanceError
Custom exceptions help with:
✔ Accurate error messages
✔ Clear problem identification
✔ Clean structure in large software
✔ Better debugging
✔ Following real-world business rules
🔷 Creating a Custom Exception Class
Custom exceptions are created using class definitions that inherit from
Python’s built-in Exception class.
✔ Basic structure
class CustomException(Exception):
pass
This creates a new exception type that behaves like a normal Python error.
🔷 Example: Creating and Raising a Simple Custom
Exception
Code:
class InvalidAgeError(Exception):
pass
age = 14
if age < 18:
raise InvalidAgeError("Age must be at least 18.")
Output:
InvalidAgeError: Age must be at least 18.
This shows your custom exception working just like built-in exceptions.
🔷 Adding Custom Messages to Exceptions
You can include detailed messages for clearer understanding.
Example:
class PasswordTooShortError(Exception):
pass
password = "abc"
if len(password) < 6:
raise PasswordTooShortError("Password must be at least 6 characters
long.")
Custom messages help the user understand what they did wrong.
🔷 Using Custom Exceptions with try–except
User-defined exceptions are handled the same way as built-in ones.
Example:
class NegativeMarksError(Exception):
pass
try:
marks = -10
if marks < 0:
raise NegativeMarksError("Marks cannot be negative.")
except NegativeMarksError as e:
print("Error:", e)
Output:
Error: Marks cannot be negative.
This is useful in systems like school management or grading software.
🔷 Creating More Structured Custom Exceptions
Larger applications often require more detail.
We can create exceptions with:
Custom attributes
Additional data
Methods inside exception class
Advanced Example:
class WithdrawalError(Exception):
def __init__(self, balance, amount):
[Link] = balance
[Link] = amount
super().__init__(f"Cannot withdraw {amount}. Balance available:
{balance}")
try:
balance = 500
amount = 800
if amount > balance:
raise WithdrawalError(balance, amount)
except WithdrawalError as e:
print(e)
Output:
Cannot withdraw 800. Balance available: 500
This shows how custom exceptions can hold extra information.
🔷 Raising Custom Exceptions Inside Functions
Just like built-in exceptions, custom exceptions can be raised from inside
functions to signal incorrect behavior.
Example:
class InvalidEmailError(Exception):
pass
def check_email(email):
if "@" not in email:
raise InvalidEmailError("Email must contain '@' symbol.")
return True
try:
check_email("[Link]")
except InvalidEmailError as e:
print("Email error:", e)
Output:
Email error: Email must contain '@' symbol.
This technique is used in form validation systems.
🔷 When to Use User-Defined Exceptions
Use custom exceptions when:
You want an error message that clearly describes a specific application
problem
Built-in exceptions don’t fit the scenario
You want to enforce business rules (banking, booking, login, inventory
systems)
You want cleaner, readable code
You are developing a large system with multiple modules
Not every program needs custom exceptions, but they become essential in
bigger systems.
🔷 Connecting to Next Topic
Now you understand:
How Python provides built-in exceptions
Why custom exceptions are needed
How to create your own exception classes
How to raise and handle them
How they help large-scale software
This completes the entire concept of Exception Handling.
The next part of your syllabus connects naturally to:
👉 File Handling
Because file handling often creates many exceptions such as:
File not found
Permission denied
Unable to write file
Unexpected end of file
File in use
So exception handling and file handling work closely together.
🔷 File Handling in Python
After understanding exceptions, the next essential part of Python
programming is file handling. File handling allows programs to store data
permanently, read information, write logs, manage documents, and interact
with the operating system. Almost every real-world application relies on files
— from databases and settings to user-uploaded content.
Python provides a simple and powerful interface to work with files through
the built-in open() function and additional modules like os and pathlib.
Exception handling and file handling often work together, because file
operations are prone to errors (e.g., missing files, incorrect paths, permission
issues). That is why this topic naturally follows exception handling.
🔷 What Is File Handling?
File handling refers to the process of:
Opening files
Reading files
Writing to files
Creating new files
Updating or appending data
Closing files
Managing directories and paths
Python supports both:
Text files (.txt, .csv, .log)
Binary files (.jpg, .exe, .mp4)
File handling ensures long-term data storage, unlike variables that disappear
when the program ends.
🔷 Why File Handling Is Important?
✔ Real-world tasks require permanent storage
For example:
Saving user accounts
Storing logs
Keeping application settings
Writing reports
Creating audit trails
✔ Communication between programs
Files let programs exchange data without direct connection.
✔ Backup and recovery
Files preserve information even when a program crashes.
✔ Automation systems
Scripts often read from files (configurations) and write outputs.
Because of the importance of file handling, Python provides clear and
consistent tools for reading and writing files.
🔷 The open() Function
Python’s built-in open() function is used to create a connection between the
program and a file.
✔ Syntax
file_object = open("filename", "mode")
✔ Meaning:
"filename" → the file to open
"mode" → the operation you want to perform
🔷 File Modes in Python
The mode defines how you want to access the file.
Below are the most important modes:
Mod Description
e
"r" Read (default)
"w" Write — overwrites file
"a" Append — adds new data
at end
"x" Create — error if exists
"b" Binary mode
"t" Text mode (default)
"r+" Read + write
"w+ Write + read (overwrites
" file)
🔷 Reading Files in Python
Reading files is one of the most common file-handling tasks.
To read any file, you must:
1. Open the file
2. Read its content
3. Process the data
4. Close the file
(We will later use with to auto-close.)
🔹 Reading an Entire File (read())
This method reads the whole content of the file at once.
✔ Example
Suppose [Link] contains:
Hello, Python!
This is a sample file.
Code:
f = open("[Link]", "r")
content = [Link]()
print(content)
[Link]()
Output:
Hello, Python!
This is a sample file.
🔹 Reading Line by Line (for loop)
This is efficient for large files.
✔ Example
f = open("[Link]", "r")
for line in f:
print([Link]()) # strip removes newline
[Link]()
🔹 Using read line()
Reads one line at a time.
✔ Example:
f = open("[Link]")
line1 = [Link]()
line2 = [Link]()
print(line1, line2)
[Link]()
🔹 Using read lines ()
Returns a list of all lines.
✔ Example:
f = open("[Link]", "r")
lines = [Link]()
print(lines)
[Link]()
Output:
['Hello\n', 'Welcome to Python\n']
🔷 Why Closing Files Is Important
When Python opens a file, it consumes system resources.
If you don’t close files:
Memory leaks may occur
File locks may remain
Unwritten data may not be saved correctly
✔ Manual Closing
f = open("[Link]")
# work
[Link]()
✔ Better Way — Using with
The best practice is to use with because it automatically closes the file even
if an exception occurs.
🔷 Reading Files Using with open()
✔ Example:
with open("[Link]", "r") as file:
content = [Link]()
print(content)
No need for [Link]().
This is safer, cleaner, and highly recommended.
🔷 Connecting to the Next Part
Now that we understand how to read files using multiple techniques, the
next step is learning how to write and create files, because reading and
writing go hand in hand.
Working with files includes:
Creating new files
Writing data into files
Updating existing files
Appending logs
These operations are crucial for real applications such as report generation,
saving records, logging activities, etc.
🔷 Writing and Creating Files in Python
After learning how to read information from files, the next essential part of
file handling is writing data to files. Writing allows programs to store
results permanently, create reports, maintain logs, save user input, and
generate documents dynamically.
Writing files is fundamental for:
Saving user data
Creating configuration files
Logging activity
Exporting results (reports, summaries)
Creating backups
Storing application output
Python provides flexible tools for writing in different modes depending on
your exact requirement.
🔹 Modes for Writing Files
To write data into a file, Python uses the following major modes:
Mod Function
e
"w" Write – creates new file or overwrites
existing file
"a" Append – adds data to end of file
"x" Create – creates new file and gives error if
file exists
"w+ Write + Read – overwrites file, then allows
" reading
Let’s explore each one in detail.
🔷 1. Writing to a File (write mode "w")
This mode is used to write data to a file.
If the file does not exist → Python creates it.
If the file exists → Python overwrites it.
✔ Example
file = open("[Link]", "w")
[Link]("Hello, this is a new file.\n")
[Link]("Writing data using Python.\n")
[Link]()
What happens?
A new file [Link] is created (if not present)
The content is written into it
Any existing data is erased
If you run the same code again:
The previous content disappears
Only the new written content remains
This is why "w" mode must be used carefully.
🔹 Understanding Overwriting Effect
🔷 2. Appending to a File (append mode "a")
Append mode is used when you want to add new data to the end of an
existing file without deleting the old data.
This is ideal for:
Log files
Chat messages
Activity tracking
Continuous data writing
✔ Example
file = open("[Link]", "a")
[Link]("This line is added at the end.\n")
[Link]()
Result:
The existing file remains intact, and the new line is added at the bottom.
🔷 3. Creating a New File Safely ("x" mode)
The "x" mode creates a new file only if it does not exist.
If the file already exists, Python raises an exception to protect the original
data.
✔ Example
try:
file = open("[Link]", "x")
[Link]("Report initialized.")
[Link]()
except FileExistsError:
print("File already exists. Creation aborted.")
Why use "x"?
Prevents accidental overwriting
Ensures safe file creation in critical systems
🔷 4. Writing Text Using with open() (Best Practice)
Instead of manually closing files, Python recommends using with open()
because it automatically closes the file even if an error occurs.
✔ Example
with open("[Link]", "w") as file:
[Link]("This file is written using with-statement.\n")
This ensures:
No file leaks
Cleaner code
Better error protection
🔷 5. Writing Multiple Lines to a File
Sometimes multiple lines need to be written at once.
We can use .writelines() for this.
✔ Example:
lines = [
"Line 1\n",
"Line 2\n",
"Line 3\n"
with open("[Link]", "w") as f:
[Link](lines)
🔷 6. Example: Saving User Input to a File
A common real-world scenario is saving user input.
✔ Example:
with open("[Link]", "a") as f:
name = input("Enter your name: ")
[Link](name + "\n")
This creates a growing list of user entries.
🔷 7. Example: Logging Application Events
Logs help track program activity.
✔ Example:
import datetime
with open("[Link]", "a") as log:
[Link](f"Program started at {[Link]()}\n")
Every time the program runs, a new log entry is added.
🔷 8. Writing Binary Files (using "wb")
Binary mode is used for non-text files like:
Images
Audio
Videos
Executables
✔ Example: Copying an Image
with open("[Link]", "rb") as src:
content = [Link]()
with open("[Link]", "wb") as dest:
[Link](content)
Binary file handling is used in:
Image processing
Download managers
File manipulators
🔷 Connection to Next Topic
Now that you understand:
How to write files
How to append data safely
How to create files
How to work with text and binary data
The importance of using with open()
The next essential part of file handling is understanding Directory
Management and the OS Module.
File handling alone is not enough; real-world programs also need to:
Create folders
Navigate directories
Rename files
Remove files
Check if paths exist
And this is where the OS Module comes in.
🔷 OS Module and Directory Management in Python
After learning how to read and write files, the natural next step is to
understand how Python works with directories (folders) and the overall file
system. In real-world applications, you rarely work with a single file — you
deal with entire structures of folders, subfolders, and files.
Python provides the OS Module, which allows your program to interact with
the operating system in a platform-independent way.
This means your code will work on:
Windows
Linux
macOS
…without needing separate instructions for each system.
The OS module is essential for:
Creating folders
Navigating directories
Renaming files
Checking file paths
Removing files and directories
Listing directory contents
Building file-management applications
🔹 Introduction to the OS Module
The os module stands for Operating System, and it provides functions to
interact with the file system and manage directories.
✔ Importing the module:
import os
Once imported, you can use all built-in functions inside os.
🔷 Getting the Current Working Directory
The current working directory (CWD) is the folder where your Python
program is operating.
✔ Example:
import os
print([Link]())
Output (example):
C:\Users\Sameer\Documents
This helps you understand where your file operations are happening by
default.
🔷 Changing the Working Directory
You can move your program into another folder.
✔ Example:
[Link]("C:/Users/Sameer/Desktop")
Now Python will read/write files in that location.
Why is this useful?
Organizing file-based programs
Running scripts inside specific folders
Accessing large datasets from specialized directories
🔷 Listing Files and Folders
To see everything inside a directory, use:
✔ Example:
files = [Link]()
print(files)
Output (example):
['[Link]', 'images', '[Link]']
This is useful for:
File exploration
Batch processing
Automatic file scanning
Organizing documents
🔷 Creating a Directory
Python can create new folders using [Link]().
✔ Example:
[Link]("new_folder")
Creates a folder named new_folder in the current directory.
Common uses:
Making folders for user uploads
Generating project directories
Organizing log files
Storing processed results
🔷 Creating Nested Directories
To create a chain of folders:
✔ Example:
[Link]("project/data/files")
This creates:
project/
data/
files/
Useful for full project initialization.
🔷 Removing Directories
✔ Removing an empty folder:
[Link]("new_folder")
✔ Removing nested directories:
[Link]("project/data/files")
Note:
These functions only work if the directory is empty.
To remove non-empty directories, you must use shutil module — but we
focus now on os.
🔷 Checking Whether a File or Directory Exists
Before performing operations, always check existence using [Link]().
✔ Example:
if [Link]("[Link]"):
print("File exists.")
else:
print("File not found.")
This prevents runtime errors like FileNotFoundError.
🔷 Checking Path Type (File or Directory)
✔ Example:
print([Link]("[Link]"))
print([Link]("project"))
This is useful for building file browsers.
🔷 Getting the Absolute Path
You can get the full absolute path of a file.
✔ Example:
path = [Link]("[Link]")
print(path)
This helps when:
Sharing file paths across modules
Debugging
Logging
Generating reports
🔷 Renaming Files and Folders
✔ Renaming a file:
[Link]("[Link]", "[Link]")
✔ Renaming a folder:
[Link]("old_folder", "new_folder")
Renaming is used in:
File organization
Versioning
Data cleaning
Automated workflows
🔷 Deleting Files
✔ Example:
[Link]("file_to_delete.txt")
Always combine with existence check:
if [Link]("file_to_delete.txt"):
[Link]("file_to_delete.txt")
This avoids errors.
🔷 Using OS Module in Real-World Scenarios
✔ 1. Organizing Downloads Folder
Automatically move all .mp3 files to a music folder.
✔ 2. Data Processing Pipelines
Create folders for input, output, logs, and temporary files.
✔ 3. File Backup Systems
Copy or rename files based on time or version.
✔ 4. Automated Report Generation
Store reports in separate date-based folders.
The os module allows Python to interact with the entire filesystem reliably
and efficiently.
🔷 Connecting to Next Topic
Now that we have covered:
Directory navigation
File & folder creation
Checking paths
Renaming and deleting files
Working safely with file systems
…it’s time to learn a more modern and Pythonic way of handling paths:
👉 pathlib Module
The pathlib module makes file and directory management easier, cleaner,
and object-oriented.
🔹 Why pathlib Is Better Than OS. path?
✔ 1. Object-Oriented
Using objects allows natural expressions like:
[Link]
[Link]()
path.is_file()
instead of calling multiple separate functions.
✔ 2. Cleaner Syntax
Instead of:
[Link]("folder", "[Link]")
You can write:
Path("folder") / "[Link]"
✔ 3. Cross-Platform
Pathlib automatically handles:
Windows paths → C:\Users\Sameer\Documents
Linux paths → /home/sameer/documents
Mac paths → /Users/sameer/Documents
No extra effort needed.
✔ 4. Integrated File Operations
Pathlib objects can:
Read files
Write files
Iterate through directories
Check attributes
without importing multiple modules.
🔷 Importing the pathlib Module
✔ Example:
from pathlib import Path
Once imported, you can create Path objects.
🔷 Creating Path Objects
Path objects represent file or directory paths.
✔ Example:
p = Path("[Link]")
print(p)
This does not create a file — it just represents the path.
🔷 Checking Whether a File or Directory Exists
✔ Example:
p = Path("[Link]")
print([Link]())
This returns:
True → if file or directory exists
False → if not
🔷 Checking Path Type
✔ Check if path is a file:
p = Path("[Link]")
print(p.is_file())
✔ Check if path is a directory:
d = Path("documents")
print(d.is_dir())
🔷 Reading Text Files with pathlib
Pathlib provides an easier way to read text.
✔ Example:
p = Path("[Link]")
content = p.read_text()
print(content)
This automatically:
Opens file
Reads file
Closes file
No manual handling required.
🔷 Writing Text Files with pathlib
Use .write_text() to quickly write content.
✔ Example:
p = Path("[Link]")
p.write_text("Hello from pathlib!")
If file does not exist → it is created
If file exists → it is overwritten
🔷 Appending to Files with pathlib
Pathlib does not have .append_text(),
so we combine the read–modify–write approach.
✔ Example:
p = Path("[Link]")
old = p.read_text()
p.write_text(old + "\nNew line added.")
Useful for logs, history, notes, etc.
🔷 Working with Binary Files
✔ Example:
p = Path("[Link]")
data = p.read_bytes()
q = Path("[Link]")
q.write_bytes(data)
Binary file processing is important for:
Images
PDFs
Videos
ZIP files
🔷 Creating Directories using pathlib
✔ Create a single folder:
Path("myfolder").mkdir()
✔ Create nested directories:
Path("projects/data/files").mkdir(parents=True)
This is equivalent to [Link]().
🔷 Iterating Through Directory Contents
Pathlib makes directory traversal easy and elegant.
✔ Example:
p = Path(".") # current directory
for item in [Link]():
print(item)
You can filter:
✔ Only files:
for file in [Link]():
if file.is_file():
print(file)
✔ Only directories:
for d in [Link]():
if d.is_dir():
print(d)
🔷 Joining Paths Using the / Operator
This is one of pathlib’s best features.
✔ Example:
folder = Path("projects")
file_path = folder / "[Link]"
print(file_path)
This results in:
projects/[Link]
This is clearer and safer than string concatenation.
🔷 Renaming and Deleting Files Using pathlib
✔ Rename:
p = Path("[Link]")
[Link]("[Link]")
✔ Delete:
p = Path("delete_me.txt")
[Link]()
Equivalent to [Link]().
🔷 Combining pathlib with Exception Handling
Since file operations can fail, pathlib works perfectly with try–except.
✔ Example:
from pathlib import Path
p = Path("[Link]")
try:
data = p.read_text()
print(data)
except FileNotFoundError:
print("The file does not exist.")
This creates powerful and stable scripts.
🔷 Real-World Use Cases of pathlib
✔ 1. Application folder setup
Creating new directories for logs, configs, backups.
✔ 2. Data science pipelines
Navigating datasets and processing CSV files.
✔ 3. File organization systems
Sorting images, documents, audio files.
✔ 4. Package development
Handling internal file structures.
✔ 5. Working with cross-platform paths
Ensures your script works on all operating systems.
🔷 Connecting to Next Topic
We now understand:
How to work with files using open()
How to manage directories using os
How to work with paths using pathlib
The final part of your required topic is a broader category that ties
everything together:
👉 Directory Management (Full Overview)
This section covers combining file handling, os module, and pathlib module
to professionally manage directories and files.
🔷 Directory Management in Python
Directory management refers to controlling and manipulating folders within
your operating system using Python. This includes tasks such as creating
folders, navigating between directories, renaming them, deleting them,
scanning their contents, and organizing files programmatically.
Directory management is essential because real-world software and scripts
often need to:
Organize files
Separate input and output data
Create backups and logs
Process thousands of files
Manage structured project folders
Clean unnecessary files
Build automation pipelines
Python provides multiple tools for directory management, especially through:
The os module
The pathlib module
Both can achieve the same goals, but pathlib offers a modern approach.
🔹 Understanding Directories in File Systems
A directory (folder) is a container that stores files and other subdirectories.
Directories form a tree-like structure:
Python can navigate and manipulate any part of this structure.
🔷 Getting the Current Working Directory
The current working directory (CWD) is where Python starts its operations.
✔ Using os:
import os
print([Link]())
✔ Using pathlib:
from pathlib import Path
print([Link]())
🔷 Changing the Working Directory
You can switch to another directory.
✔ Using os:
[Link]("C:/Users/Sameer/Desktop")
✔ Using pathlib:
path = Path("C:/Users/Sameer/Desktop")
[Link](path)
Changing directories is necessary when your program deals with files located
in different places.
🔷 Listing Directory Contents
To see what files and folders exist inside a directory:
✔ Using os:
print([Link]())
✔ Using pathlib:
for item in Path(".").iterdir():
print(item)
Pathlib’s output is more structured because each element is a Path object.
🔷 Creating Directories
✔ Creating a single folder (os):
[Link]("new_folder")
✔ Creating nested folders (os):
[Link]("projects/data/logs")
✔ Creating folder with pathlib:
Path("new_folder").mkdir()
✔ Creating nested folders with pathlib:
Path("projects/data/logs").mkdir(parents=True)
🔷 Removing Directories
Directories must be empty to remove them using os.
✔ Using os:
[Link]("empty_folder")
✔ Removing nested empty directories:
[Link]("projects/data/logs")
✔ Using pathlib:
Path("empty_folder").rmdir()
Important:
To delete non-empty directories, you need the shutil module:
import shutil
[Link]("folder_name")
This deletes everything inside the folder.
🔷 Checking Existence of Directories
Before performing operations, always confirm whether the directory exists.
✔ Using os:
if [Link]("myfolder"):
print("Folder exists.")
✔ Using pathlib:
p = Path("myfolder")
print([Link]())
🔷 Checking Whether Path Is File or Directory
✔ os:
[Link]("myfolder")
[Link]("[Link]")
✔ pathlib:
p = Path("[Link]")
print(p.is_file())
print(p.is_dir())
🔷 Renaming Directories
✔ Using os:
[Link]("old_folder", "new_folder")
✔ Using pathlib:
Path("old_folder").rename("new_folder")
Useful when organizing project structure.
🔷 Moving Files Between Directories
The shutil module is used for moving.
✔ Example:
import shutil
[Link]("[Link]", "backup/")
This is crucial for automated sorting systems.
🔷 Iterating Through Files in a Directory
✔ Using pathlib:
p = Path("documents")
for file in [Link]():
if file.is_file():
print("File:", file)
✔ Filtering by file type:
for file in [Link]("*.txt"):
print(file)
This is extremely useful for batch-processing text files, CSVs, logs, etc.
🔷 Recursively Searching Directories
✔ Using pathlib:
for file in Path(".").rglob("*.py"):
print(file)
This scans all subdirectories too.
🔷 Creating a Directory Structure Programmatically
A common real-world example is initializing a project folder.
✔ Example:
from pathlib import Path
root = Path("project")
(root / "input").mkdir(parents=True, exist_ok=True)
(root / "output").mkdir(exist_ok=True)
(root / "logs").mkdir(exist_ok=True)
print("Project structure created.")
This creates:
project/
input/
output/
logs/
🔷 Directory Management: Combined Example
Below is a complete example combining reading, writing, directory creation,
and path checking.
✔ Example:
from pathlib import Path
project = Path("my_app")
(project / "data").mkdir(parents=True, exist_ok=True)
file_path = project / "data" / "[Link]"
# Write file
file_path.write_text("User1\nUser2\n")
# Read file
print("File content:")
print(file_path.read_text())
# List directory
print("Files in /data:")
for f in (project / "data").iterdir():
print(f)
This example shows how simple directory management becomes with
pathlib.
🔷 Directory Management in Real-World Applications
Directory management is essential in:
✔ Data Analytics
Organizing raw data, processed data, results, visualizations.
✔ Web Applications
Managing uploaded files, logs, media files, configuration.
✔ Automation Scripts
Sorting files automatically, creating backups, cleaning folders.
✔ Machine Learning
Separating training, validation, and test datasets.
✔ System Tools
Writing scripts to monitor file systems or generate reports.
🔷 Final Connection
You now understand:
Exception Handling
Built-in Exceptions
User-defined Exceptions
File Reading
File Writing
OS Module
Pathlib Module
Directory Management
Together, these topics form the backbone of real-world file and error-handling
tasks in Python.