DEV Community

Tejas Shinkar
Tejas Shinkar

Posted on

Modules (Deep Dive), File Handling, Exception Handling

šŸ“Œ Key Concepts Overview

Concept One-Line Definition
Module A .py file containing reusable functions/variables
dir(module) Lists all functions/attributes available in a module
sys.path List of directories Python searches when importing a module
File Any container that stores code/data for reuse
Text vs Binary file Text = human-readable (.txt, .py); Binary = everything else
File mode Controls how a file is opened — r, w, a, r+, w+, a+
Cursor Pointer tracking current read/write position in a file
with open() Context manager — auto-closes the file, even on error
Exception A runtime error that can crash a program if unhandled
try-except Catches runtime errors so the program continues gracefully

šŸ“¦ Part 1 — Modules (Deep Dive)

What's Inside a Module

import math
print(dir(math))     # lists every function/constant available in the math module

math.ceil(5/2)        # 3 — rounds UP
math.factorial(5)     # 120
math.pow(2, 3)        # 8.0 — note: returns FLOAT, unlike ** which can return int
math.sin(0.45)
angle = math.radians(0.45)
Enter fullscreen mode Exit fullscreen mode

āš ļø Common Mistake: Calling ceil(5/2) WITHOUT importing math first → NameError: name 'ceil' is not defined. You must import math and use math.ceil(...).

3 Ways to Import

1. Import the whole module — access via module.function()

import math
math.pow(2, 3)
math.sqrt(5)
Enter fullscreen mode Exit fullscreen mode

2. Import specific functions — access directly, no prefix needed

from math import pow
pow(2, 3)              # āœ… works directly

from math import pow, factorial, sqrt, ceil
sqrt(5)
factorial(6)
ceil(5/2)               # āœ… now works without math. prefix
Enter fullscreen mode Exit fullscreen mode

3. Import everything with * — use ANY function directly

from math import *
sin(0.5)               # works without prefix

# āš ļø DANGER: if two modules have a function with the SAME name,
# the second import SILENTLY OVERWRITES the first
from numpy import *
from pandas import *
# If both have a function called 'mean', whichever was imported LAST wins
# This can cause confusing bugs — avoid `import *` in real projects
Enter fullscreen mode Exit fullscreen mode

dir() — See What's Currently Available in Your Namespace

print(dir())          # shows ALL names currently defined/imported in your session

import math
print(dir())           # now includes 'math'

from math import pow
print(dir())            # now ALSO includes 'pow' directly
Enter fullscreen mode Exit fullscreen mode

Best Practice for DevOps scripts: Prefer import module_name and call module.function(). It's explicit, avoids name collisions, and makes code easier to read/maintain — critical when multiple engineers work on the same automation scripts.

Renaming a Module on Import (Aliasing)

import pandas as pd      # 'pd' is now the alias — standard convention
import boto3              # AWS SDK for Python — you'll use this constantly later
import requests            # for making HTTP API calls
Enter fullscreen mode Exit fullscreen mode

These three are core DevOps/Cloud libraries:

Library Used for
boto3 AWS SDK — create/manage EC2, S3, IAM, etc. from Python
requests Calling REST APIs, webhooks, health-check endpoints
pandas Processing CSV/log data, reporting

Creating a User-Defined Module

# Step 1: create a .py file (e.g., module.py) with function definitions:
# def square(x):
#     return x ** 2

# Step 2: import it like any other module
import module
module.square(2)         # 4
Enter fullscreen mode Exit fullscreen mode

sys.path — Where Python Looks for Modules

import sys
print(sys.path)           # list of directories Python searches for modules

# If your module isn't in any of these folders, import fails with ModuleNotFoundError
# Fix: add the folder to the search path
sys.path.append(r"C:\Users\Lenovo\Desktop")
print(sys.path)            # now includes your custom folder

import module1              # now Python can find it
Enter fullscreen mode Exit fullscreen mode

DevOps relevance: Understanding sys.path matters when organizing automation projects with custom helper modules (e.g., aws_utils.py, log_parser.py) that need to be importable from your main scripts.


šŸ“ Part 2 — File Handling

What Is a File?

A file is any container used to store code or data for reuse — could be .txt, .py, .csv, .json, .log, images, audio, etc.

Two Categories in Python

Type Examples Description
Text files .txt, .py, .csv, .log Human-readable
Binary files images, audio, video, .pdf, .xlsx Everything else

The 4 File Operations

Create → Open
Read   → read()
Update → write() / append
Delete → close (releases the file resource)
Enter fullscreen mode Exit fullscreen mode

Opening & Closing a File

# Syntax: file_handle = open('file_name', 'mode')
f = open('test.txt', 'r')
# ... do something ...
f.close()        # MUST close — otherwise risk losing unsaved data / locked file
Enter fullscreen mode Exit fullscreen mode

Key File Functions

Function Purpose
write() Write data to the file
read() Read data from the file
tell() Returns current cursor position (index)
seek(n) Moves cursor to position n

šŸ”‘ Part 3 — File Modes (THE Core of This Class)

'r' — Read Mode (Default)

f = open('test.txt', 'r')
print(f.tell())       # 0 — cursor starts at beginning
print(f.read())        # prints file content
print(f.tell())         # now at end of file (cursor moved after reading)
f.close()
Enter fullscreen mode Exit fullscreen mode

Rules:

  • File must already exist → else FileNotFoundError
  • Can READ, cannot WRITE
  • Cursor starts at position 0 (beginning)
f = open('test.txt', 'r')
f.write('Trying to write...')    # āŒ io.UnsupportedOperation: not writable
f.close()
Enter fullscreen mode Exit fullscreen mode

'w' — Write Mode

f = open('test.txt', 'w')
f.write('Everything has been removed from the file')
f.close()
Enter fullscreen mode Exit fullscreen mode

Rules:

  • If file exists → WIPES all previous content (overwrites completely!)
  • If file doesn't exist → creates a new one
  • Can WRITE, cannot READ
f = open('test.txt', 'w')
f.write('New content')
print(f.read())        # āŒ io.UnsupportedOperation: not readable
f.close()
Enter fullscreen mode Exit fullscreen mode

āš ļø Biggest danger of 'w' mode: Opening an existing file in 'w' mode instantly destroys its old content — even before you write anything new. Use with extreme caution on important files (this is exactly how production log files or configs get accidentally wiped).

'a' — Append Mode

f = open('test.txt', 'a')
print(f.tell())          # cursor starts at END of existing content (not 0!)
f.write('This is Python class')
print(f.tell())            # moved further right after writing
f.close()
Enter fullscreen mode Exit fullscreen mode

Rules:

  • If file exists → cursor placed at the END; new writes are appended, old content preserved
  • If file doesn't exist → creates a new file
  • Can WRITE, cannot READ
  • seek() does NOT work for repositioning writes — append mode always writes at the end regardless of where you seek() to
f = open('test.txt', 'a')
f.seek(20)                    # tries to move cursor to position 20
f.write('This is weekend batch')   # still gets appended at the TRUE end, not position 20
f.close()
Enter fullscreen mode Exit fullscreen mode

'r+' — Read AND Write Mode

f = open('test.txt', 'r+')
print(f.tell())          # 0
print(f.read())           # reads full content, cursor moves to end
f.close()
Enter fullscreen mode Exit fullscreen mode

Rules:

  • File must exist → else FileNotFoundError
  • Can BOTH read and write
  • seek() works — lets you reposition before writing
  • āš ļø Writing OVERWRITES characters starting at the cursor position (doesn't insert — it replaces existing characters character-by-character)
f = open('test.txt', 'r+')
f.seek(3)
f.write('hey')     # overwrites whatever 3 characters started at position 3
f.close()
Enter fullscreen mode Exit fullscreen mode

'w+' — Write AND Read Mode

f = open('test.txt', 'w+')
f.write('This is Python class')
print(f.tell())            # cursor is now at the end
f.seek(0)                   # must seek back to 0 to read what you just wrote!
print(f.read())              # 'This is Python class'
f.close()
Enter fullscreen mode Exit fullscreen mode

Rules:

  • If file exists → wipes content (just like 'w')
  • If file doesn't exist → creates new
  • Can BOTH write and read — but you must seek(0) after writing if you want to read what you just wrote (cursor is at the end after writing)

'a+' — Append AND Read Mode

with open('test.txt', 'a+') as f:
    print(f.tell())                       # at end (existing content length)
    f.write('\nThis is weekend batch')     # appends
    print(f.tell())
    f.seek(0)                               # go back to start to read everything
    print(f.tell())
    print(f.read())                          # full file content, old + new
Enter fullscreen mode Exit fullscreen mode

Rules:

  • Preserves existing content (like 'a')
  • Can read too — but must seek(0) first
  • seek() does NOT work to reposition WRITES — always appends at true end

šŸ“Š Mode Comparison Table (Memorize This)

Mode File must exist? Existing content Read? Write? Cursor start
r Yes (else error) Preserved āœ… āŒ Beginning
w No (creates) Wiped āŒ āœ… Beginning
a No (creates) Preserved āŒ āœ… End
r+ Yes (else error) Preserved (overwritten on write) āœ… āœ… Beginning
w+ No (creates) Wiped āœ… āœ… Beginning
a+ No (creates) Preserved āœ… āœ… End

šŸ›”ļø with open() — The Recommended Way

# Same as open(), but AUTO-CLOSES the file when the block ends — even if an error occurs
with open('test.txt', 'r') as f:
    print(f.tell())
    print(f.read())
    print(f.tell())
print(f.closed)        # True — automatically closed once outside the 'with' block
print(f.read())          # āŒ ValueError: I/O operation on closed file
Enter fullscreen mode Exit fullscreen mode

Why this matters in DevOps: Forgetting f.close() in a long-running automation script can leak file handles, lock files on the OS, or lose buffered writes if the script crashes. with open() eliminates this entire class of bugs — always prefer it over manual open()/close().


šŸ”§ Part 4 — Functions on a File

read() — Read Entire Content as One String

with open('test.txt', 'r') as f:
    print(f.tell())          # 0
    data = f.read()
    print(f.tell())           # moved to end

print(data, type(data))        # full content, <class 'str'>
Enter fullscreen mode Exit fullscreen mode

readline() — Read ONE Line at a Time

with open('test.txt', 'r') as f:
    print(f.tell())
    print(f.readline(), type(f.readline()))   # reads from cursor up to end of THAT line
    print(f.tell())

# seek() lets you jump to a specific position before reading a line
with open('test.txt', 'r') as f:
    f.seek(26)
    print(f.readline())        # reads the rest of the line starting at position 26
Enter fullscreen mode Exit fullscreen mode

readlines() — Read ALL Lines as a LIST

with open('test.txt', 'r') as f:
    data = f.readlines()

print(data, type(data))     # ['line1\n', 'line2\n', ...] <class 'list'>

for i in data:
    print(i)                  # iterate line by line
Enter fullscreen mode Exit fullscreen mode

read() vs readline() vs readlines():

Method Returns Use case
read() One big string (whole file) Small files, need full text
readline() One string (single line) Process huge files line-by-line (memory efficient)
readlines() A list of strings (each line) Need to loop/count/index by line

write() — Write a String

with open('test.txt', 'w+') as f:
    f.write('This is Python Class')
    f.write('\nThis is Devops batch')     # \n needed for new line — write() does NOT auto-newline
    f.write('\nThis is weekend Class')
    f.seek(0)
    print(f.read())
Enter fullscreen mode Exit fullscreen mode

writelines() — Write a LIST of Strings

lst = ['Python\n', 'DevOps\n', 'Linux\n', 'AWS\n']
with open('test.txt', 'w+') as f:
    f.writelines(lst)            # writes each list item — \n must be included manually
    f.seek(0)
    print(f.read())
Enter fullscreen mode Exit fullscreen mode

āš ļø writelines() does NOT add newlines automatically — if your list items don't have \n, everything gets written on one continuous line.


ā˜ļø DevOps / Cloud Use Cases

# 1. Reading a server config file
with open('server_config.txt', 'r') as f:
    config = f.read()
    print(config)

# 2. Appending to a log file (most common DevOps file pattern)
with open('deployment.log', 'a+') as f:
    f.write('\n[INFO] Deployment started at 14:30')

# 3. Writing a fresh report each run
with open('health_report.txt', 'w') as f:
    f.write('Server Health Report\n')
    f.write('All systems operational\n')

# 4. Reading line-by-line for large log files (memory efficient)
with open('access.log', 'r') as f:
    for line in f:
        if 'ERROR' in line:
            print(line.strip())

# 5. Counting errors in a log file
with open('app.log', 'r') as f:
    lines = f.readlines()
error_count = sum(1 for line in lines if line.startswith('ERROR'))
print(f'Total errors: {error_count}')

# 6. Writing a list of server names to a file (inventory)
servers = ['web-01\n', 'web-02\n', 'db-01\n']
with open('inventory.txt', 'w') as f:
    f.writelines(servers)
Enter fullscreen mode Exit fullscreen mode

āš ļø Part 5 — Errors: Two Types

1. Syntax Error (Compile-time error)
   — caught BEFORE the program runs
   — e.g., missing colon, unmatched quotes

2. Runtime Error (Logical / Exception)
   — happens WHILE the program runs
   — e.g., dividing by zero, file not found, wrong data type
Enter fullscreen mode Exit fullscreen mode
print('Devops)        # āŒ SyntaxError — unclosed string, caught immediately, nothing runs

print('Hello')
print(10/0)             # āŒ ZeroDivisionError — this is a RUNTIME error
print('Code working fine')   # never reached — program crashes at the error above
Enter fullscreen mode Exit fullscreen mode

Key takeaway: A syntax error stops the ENTIRE program from running, even lines before it. A runtime error stops execution AT that line — lines before it already ran successfully.


🧯 Part 6 — Exception Handling

Why Exception Handling?

To handle runtime errors gracefully so the program doesn't crash suddenly — especially important for automation scripts that run unattended (cron jobs, CI/CD pipelines, monitoring scripts).

Basic try-except

a = int(input('Enter a number: '))
b = int(input('Enter the second number: '))
try:
    print(a/b)                          # suspicious code goes here
except:
    print("Denominator can't be zero")   # runs ONLY if try block raises an error
print('Hello')                            # this STILL runs — program didn't crash!
Enter fullscreen mode Exit fullscreen mode

Multiple Statements Inside try

try:
    a = int(input('Enter a number: '))
except:
    print('Only integers are allowed')

print('Hello')

try:
    print(a/b)
except:
    print("Denominator can't be zero")
print('Hello')
Enter fullscreen mode Exit fullscreen mode

Catching the Actual Exception with as e

try:
    a = int(input('Enter a number: '))
    b = 10/a
    lst = [1,2,3,4,5]
    print(lst[a])
except Exception as e:
    print(e)              # prints the ACTUAL error message — much more useful for debugging
Enter fullscreen mode Exit fullscreen mode
print(dir(Exception))     # see all exception attributes/methods
Enter fullscreen mode Exit fullscreen mode

Specific Exception Types — Best Practice

try:
    a = int(input('Enter a number: '))
except ValueError:
    print('Only numbers are allowed')

try:
    b = 10/a
except ZeroDivisionError:
    print('Cannot divide by zero')

try:
    lst = [1,2,3,4,5]
    print(lst[a])
except IndexError:
    print('The index is out of range')
Enter fullscreen mode Exit fullscreen mode

Why use specific exceptions instead of bare except:?

  • Bare except: catches EVERYTHING — including bugs you didn't anticipate, masking real problems
  • Specific exceptions (ValueError, ZeroDivisionError, IndexError, FileNotFoundError) let you handle each error type appropriately and give precise feedback

Common Exception Types Seen in Class

Exception Triggered by
ValueError Casting invalid data, e.g. int('abc')
ZeroDivisionError Dividing by zero
IndexError Accessing a list index that doesn't exist
FileNotFoundError Opening a non-existent file in 'r' mode
Exception Generic catch-all (base class for most exceptions)
# FileNotFoundError example
with open('test11.txt', 'r') as f:    # file doesn't exist
    print(f.read())
# āŒ FileNotFoundError: [Errno 2] No such file or directory: 'test11.txt'
Enter fullscreen mode Exit fullscreen mode

ā˜ļø DevOps / Cloud Use Cases (Exception Handling)

# 1. Resilient config file reader — won't crash the whole automation script
try:
    with open('config.txt', 'r') as f:
        config = f.read()
except FileNotFoundError:
    print('āš ļø Config file missing — using defaults')
    config = 'default_config'

# 2. Safe API call handling (will be used with requests later)
import requests
try:
    response = requests.get('https://api.example.com/health', timeout=5)
    print(response.status_code)
except requests.exceptions.RequestException as e:
    print(f'API call failed: {e}')

# 3. Safe division for resource utilisation percentage
try:
    used = 80
    total = 0
    percentage = (used / total) * 100
except ZeroDivisionError:
    print('āš ļø Total capacity is zero — check configuration')

# 4. Validating user-provided port number
try:
    port = int(input('Enter port: '))
except ValueError:
    print('āŒ Port must be a number')
    port = None

# 5. Retry loop combined with exception handling (polling pattern)
import time
for attempt in range(3):
    try:
        with open('status.txt', 'r') as f:
            status = f.read()
        break
    except FileNotFoundError:
        print(f'Attempt {attempt+1}: status file not ready yet')
        time.sleep(2)
Enter fullscreen mode Exit fullscreen mode

āŒ Common Mistakes

Mistake Code Fix
Reading in 'w' mode open('f.txt','w'); f.read() 'w' mode is write-only — use 'r+' or 'w+'
Writing in 'r' mode open('f.txt','r'); f.write(...) 'r' mode is read-only — use 'w', 'a', or 'r+'
Forgetting seek(0) after writing in w+/a+ Write then immediately read() → gets empty string f.seek(0) before reading
Using 'w' on an important file Instantly wipes existing content Use 'a' to preserve data, or back up first
seek() in append mode Expecting seek() to control WHERE append writes Append mode always writes at the true end regardless
Bare except: swallowing all errors Hides real bugs, hard to debug Catch specific exceptions: except ValueError:
Forgetting f.close() (without with) File handle stays open, risk of data loss Always use with open(...) as f:
writelines() without \n All text runs together on one line Include \n in each list item
SyntaxError stops everything A typo like 'Devops) halts the whole program Fix the syntax before runtime errors even matter

šŸŽÆ Interview Points

  1. "Difference between import module and from module import function?"
    → import module requires module.function() calls — explicit and avoids name collisions. from module import function lets you call function() directly but risks overwriting names from other imports.

  2. "Why avoid from module import *?"
    → It pollutes the namespace and can silently overwrite functions/variables from other modules with the same name, causing hard-to-debug bugs.

  3. "Difference between 'r+' and 'w+' mode?"
    → 'r+' requires the file to exist and preserves content. 'w+' creates the file if missing and wipes existing content immediately upon opening.

  4. "Why use with open() instead of open() + close()?"
    → with guarantees the file is closed automatically — even if an exception occurs inside the block — preventing resource leaks and data loss.

  5. "Difference between read(), readline(), and readlines()?"
    → read() returns the whole file as one string. readline() returns one line at a time (memory efficient for huge files). readlines() returns a list of all lines.

  6. "Why does seek() not work for repositioning writes in append mode?"
    → Append mode ('a'/'a+') is OS-level guaranteed to always write at the true end of the file, regardless of cursor position — this prevents accidental data corruption from concurrent writers.

  7. "What's the difference between a syntax error and a runtime error?"
    → Syntax errors are caught before execution begins (e.g., missing colon) and stop the program entirely. Runtime errors occur during execution (e.g., division by zero) and only affect code from that point onward — code before it has already run.

  8. "Why use specific exceptions (ValueError, ZeroDivisionError) instead of a bare except:?"
    → Specific exceptions let you handle different failure modes appropriately and avoid silently catching bugs you didn't anticipate. Bare except: can mask real problems.

  9. "What's the difference between except: and except Exception as e:?"
    → except: catches the error but gives you no information about it. except Exception as e: captures the actual exception object so you can inspect/print/log the real error message.


šŸ“š Knowledge Base — Quick Revision

# ── MODULE IMPORTS ──────────────────────────────────────────
import math                      # math.func()
from math import sqrt            # sqrt() directly
from math import *                # everything directly (avoid in real code)
import pandas as pd                # aliasing
import sys; sys.path.append(dir)   # add custom module search path

# ── FILE MODES ──────────────────────────────────────────────
'r'    # read only, file must exist
'w'    # write only, WIPES existing content, creates if missing
'a'    # write only, APPENDS at end, creates if missing
'r+'   # read + write, file must exist, cursor at start
'w+'   # read + write, WIPES content, creates if missing
'a+'   # read + write, APPENDS, creates if missing

# ── FILE OPERATIONS ─────────────────────────────────────────
with open('file.txt', 'mode') as f:   # auto-closes — ALWAYS prefer this
    f.read()          # whole file as one string
    f.readline()       # one line at a time
    f.readlines()       # list of all lines
    f.write('text')      # write a string (no auto \n)
    f.writelines(lst)     # write a list of strings (no auto \n)
    f.tell()                # current cursor position
    f.seek(n)                 # move cursor to position n

# ── EXCEPTION HANDLING ──────────────────────────────────────
try:
    risky_code()
except SpecificError:
    handle_it()
except Exception as e:
    print(e)            # see the actual error

# Common exceptions:
# ValueError        — bad type conversion
# ZeroDivisionError — division by zero
# IndexError        — list index out of range
# FileNotFoundError — file doesn't exist (in 'r' mode)
Enter fullscreen mode Exit fullscreen mode

šŸ‹ļø Practice Questions

Easy

  1. Open a file notes.txt in write mode, write 3 lines (using \n), close it, then reopen in read mode and print the content.
  2. What's the difference between f.read() and f.readlines()? Demonstrate both on the same file.
  3. Write a try-except block that safely converts user input to an integer, catching ValueError if the input isn't numeric.

Medium

  1. Create a file log.txt using 'a+' mode. Append 3 log lines on 3 separate runs (simulate by calling the write block 3 times). Read and print the full file after the 3rd append.
  2. Write a script using try-except with THREE specific except blocks (ValueError, ZeroDivisionError, IndexError) that takes a number from the user, divides 100 by it, and accesses that index in a 5-element list.
  3. Explain (with code) why opening an existing file in 'w' mode and immediately closing it without writing anything still destroys the original content.

DevOps-Focused

  1. Log File Analyzer: Create a file server.log with writelines() containing a mix of INFO, WARN, and ERROR lines. Then read it back with readlines() and count how many lines start with each level. Wrap the file-reading part in a try-except FileNotFoundError block.
  2. Safe Config Loader: Write a function load_config(filename) that tries to open and read a config file. If the file doesn't exist, catch FileNotFoundError and return a default config string instead of crashing. Test it with both an existing and a non-existing filename.

Top comments (0)