Skip to content

Files I/O, Exceptions and Modules

File handling, exception handling, and modules are three very important parts of Python.
Almost every real project uses them. File handling helps you store and read data. Exceptions help you handle errors safely. Modules help you organize your code into smaller reusable parts.


Files are used to store data permanently. When your program ends, variables are lost, but files keep the data saved on disk. Python can work with many types of files like text files, binary files, CSV files, logs, and more.

The basic process of working with files is:

  1. Open the file
  2. Perform operations (read/write)
  3. Close the file

ModeMeaning
rRead file (must exist)
wWrite (overwrite file)
aAppend (add at end)
xCreate new file
bBinary mode
tText mode
+Read and write

You can open a file using open() and manually close it.

file = open("notes.txt", "r", encoding="utf-8")
content = file.read()
print(content)
file.close()

Explanation:

  • open() opens the file
  • read() reads content
  • close() releases the file

Problem: If an error happens before close(), the file may remain open, which can cause bugs or memory issues.


The with statement automatically handles closing the file, even if an error occurs.

with open("notes.txt", "r", encoding="utf-8") as file:
content = file.read()
print(content)

Why use with:

  • Automatically closes file
  • Safer and cleaner
  • Prevents resource leaks
graph TD Start --> Open["Open file"] Open --> Work["Read or write data"] Work --> Exit["Exit block"] Exit --> Close["File closes automatically"]

Reading means getting data from a file into your program.

with open("notes.txt", "r", encoding="utf-8") as file:
content = file.read()
with open("notes.txt", "r", encoding="utf-8") as file:
for line in file:
print(line.strip())

Line-by-line reading is better for large files.


Writing replaces the file content, while appending adds new content.

# Write
with open("notes.txt", "w", encoding="utf-8") as file:
file.write("First line\n")
# Append
with open("notes.txt", "a", encoding="utf-8") as file:
file.write("Second line\n")

Binary files store data as raw bytes instead of text. These are used for images, videos, PDFs, etc.

data = b"Hello"
with open("data.bin", "wb") as file:
file.write(data)
with open("data.bin", "rb") as file:
content = file.read()
print(content)

Sometimes you want to save Python objects like lists or dictionaries directly into a file. This is called serialization.

import pickle
data = {"name": "Sahil", "age": 21}
# Save object
with open("data.pkl", "wb") as file:
pickle.dump(data, file)
# Load object
with open("data.pkl", "rb") as file:
loaded = pickle.load(file)
print(loaded)

Explanation:

  • dump() → store object
  • load() → retrieve object

pathlib is a modern way to handle file paths. It is easier and cleaner.

from pathlib import Path
path = Path("data") / "notes.txt"
print(path)

It works correctly on all operating systems.


Exceptions are errors that occur while a program is running. Instead of crashing the program, Python allows you to handle these errors.


ExceptionMeaning
FileNotFoundErrorFile not found
ZeroDivisionErrorDivision by zero
ValueErrorInvalid value
TypeErrorWrong type
IndexErrorInvalid index
KeyErrorMissing key

try:
number = int("42")
except ValueError:
print("Invalid number")
else:
print("Success:", number)
finally:
print("Always runs")

Explanation:

  • try → code that may fail
  • except → runs if error occurs
  • else → runs if no error
  • finally → always runs
graph TD Start --> Try Try -->|No error| Else Try -->|Error| Except Else --> Finally Except --> Finally Finally --> End

You can create errors manually when something is wrong.

def set_age(age):
if age < 0:
raise ValueError("Age cannot be negative")
return age

Custom exceptions make your program more clear.

class InvalidAmountError(Exception):
pass
def withdraw(balance, amount):
if amount > balance:
raise InvalidAmountError("Not enough balance")
return balance - amount

A module is a Python file that contains reusable code. It helps you organize your program and avoid repeating code.


import math
import math as m
from math import sqrt
from math import sqrt as square_root

helpers.py

def clean_text(text):
return text.strip().lower()

main.py

from helpers import clean_text
print(clean_text(" Hello "))

This allows a file to act both as a script and a module.

def main():
print("Running directly")
if __name__ == "__main__":
main()

This block runs only when the file is executed directly.


graph TD Script --> Import Import --> Load Load --> Cache["Loaded once"] Cache --> Use

A package is a folder that contains multiple modules. It helps organize large projects.

Example structure:

project/
├── main.py
├── utils/
│ ├── __init__.py
│ ├── helpers.py
│ └── parser.py

from utils.helpers import clean_text

Relative imports are used inside packages to refer to files based on location.

from .helpers import clean_text

This means: import from the same folder.


from ..config import settings

This means: go one folder up, then import.


project/
├── app/
│ ├── main.py
│ └── utils/
│ └── helper.py

Inside helper.py:

from ..main import something

Explanation:

  • .. → go to parent folder (app)
  • then import main.py

TypeExampleMeaning
Absolutefrom utils.helpers import clean_textFull path
Relativefrom .helpers import clean_textBased on current file

Absolute imports are easier to read. Relative imports are useful inside packages.