Unit 3: File Handling and Exception Handling
I. Orientation
Python programs interact with two important sources of difficulty: operations may fail during execution, and data may need to be stored outside the program. Exception handling provides a controlled response to runtime errors, while file handling allows programs to create, read, modify, and preserve data in files. Python’s json module extends file handling to structured data represented as JSON text.
- Runtime principle: Python executes statements sequentially, but errors such as
FileNotFoundErrororZeroDivisionErrorinterrupt normal execution unless handled. - Exception principle: An exception is an object describing an abnormal event; it can be raised, caught, handled, or allowed to terminate the program.
- File principle: A file is opened through a file object, used with an operation such as
read()orwrite(), and then closed. - Resource convention:
withstatements are preferred because they close files automatically, including when an exception occurs. - Data convention: Text files store characters, whereas JSON files store structured data such as objects, arrays, strings, numbers, Boolean values, and
null. - Reliability principle: Good programs anticipate specific failures, handle only what they can meaningfully handle, and preserve useful diagnostic information.
II. Built-in exceptions — Python’s predefined error classes
A built-in exception is a predefined Python class representing a common category of runtime failure. Python raises these exceptions automatically when an operation violates its rules.
A. Definition and hierarchy
Built-in exceptions form a class hierarchy, allowing a specific exception to be caught before a broader category such as Exception.
- Base classes: Most application-level exceptions inherit from
Exception;BaseExceptionis higher in the hierarchy and also includes control-flow exceptions such asSystemExitandKeyboardInterrupt. - Specificity:
ValueErrorindicates an inappropriate value, whileTypeErrorindicates an inappropriate type. - Inheritance example:
FileNotFoundErroris a subclass ofOSError, so either class can catch a missing-file error, although the specific class is clearer. - Error message:
str(error)commonly provides a human-readable explanation, such as the path that could not be opened.
B. Common built-in exceptions
Recognizing the cause of common exceptions helps select an appropriate handler.
NameError: An identifier is not defined;print(total)raises it iftotalhas never been assigned.SyntaxError: Python cannot parse the source, for exampleif x > 2without a following colon.TypeError: An operation uses incompatible types;"Age: " + 20raisesTypeError.ValueError: The type is acceptable but the value is not;int("abc")cannot convert the string.IndexError: A sequence index is outside its valid range;[4, 5][2]is invalid.KeyError: A dictionary key is absent;{"a": 1}["b"]raises it.ZeroDivisionError: An arithmetic division uses zero as the divisor, such as10 / 0.FileNotFoundError: An operation attempts to open a path that does not exist.PermissionError: The operating system denies a requested file operation.JSONDecodeError: Thejsonmodule cannot interpret text as valid JSON; it is commonly caught when reading malformed JSON.
III. Try and except — controlling runtime failures
try and except provide structured exception handling. Statements that may fail are placed in try, and one or more except clauses define responses for selected exceptions.
A. Purpose and basic syntax
The purpose of try and except is to prevent an anticipated runtime failure from causing uncontrolled program termination.
- Protected block: The
tryblock contains statements whose exceptions should be handled. - Handler block: An
exceptblock runs only when a matching exception is raised. - Specific handling: Catching
ValueErrorseparately fromFileNotFoundErrorallows different corrective actions. - Exception object:
as errorbinds the raised exception to a variable for inspection.
try:
quantity = int(input("Quantity: "))
except ValueError as error:
print("Enter a whole number:", error)Here, quantity is intended to hold an integer, and error refers to the ValueError object if conversion fails.
B. else, finally, and multiple handlers
The optional else and finally clauses separate successful processing from cleanup.
- Multiple handlers: Python checks
exceptclauses from top to bottom; specific exceptions should appear before broad exceptions. else: Runs only when thetryblock finishes without an exception, making successful processing explicit.finally: Runs whether an exception occurs or not, so it is suitable for essential cleanup such as releasing a resource.- Bare
except:except:catches nearly everything and can hide programming defects;except Exception:is usually safer but should still be used deliberately. - Propagation: If no handler matches, the exception moves to an outer caller; this is called propagation.
try:
number = int("42")
except ValueError:
print("Invalid number")
else:
print(number * 2)
finally:
print("Conversion attempt finished")C. Raising and handling exceptions
Programs can use raise when an input violates a rule even though Python’s operation itself succeeds.
- Validation:
raise ValueError("age must not be negative")explicitly rejects an invalid age. - Re-raising: A handler can use bare
raiseto pass the original exception to a higher-level function after logging or cleanup. - Chaining:
raise RuntimeError("configuration failed") from errorpreserves the original cause inerror. - Scope: The
tryblock should be narrow; wrapping an entire program can incorrectly attribute unrelated failures to one operation.
IV. User-defined exceptions — application-specific errors
A user-defined exception is a class created by the programmer for a meaningful error condition that built-in classes do not express precisely.
A. Definition and design
User-defined exceptions communicate domain-specific failures while retaining Python’s standard exception mechanism.
- Inheritance: A custom exception normally inherits from
Exception, not directly fromBaseException. - Naming: Exception class names conventionally end with
Error, such asInsufficientBalanceError. - Meaning: A custom class distinguishes a business rule from a technical failure such as
TypeError. - Optional data: The exception can store useful attributes, such as an account number or rejected amount.
class NegativeMarkError(Exception):
"""Raised when a mark is below zero."""
try:
mark = -3
if mark < 0:
raise NegativeMarkError("Mark cannot be negative")
except NegativeMarkError as error:
print(error)Here, NegativeMarkError represents a validation rule, and error contains its message.
B. Use and limitations
Custom exceptions are most useful at clear boundaries between validation, processing, and presentation.
- Caller control: A calling function can catch
NegativeMarkErrorand display a suitable message without examining text messages. - Separation: The exception class defines what went wrong, while the handler decides what to do.
- Avoid overuse: A custom exception is unnecessary when an existing class, such as
ValueError, already communicates the condition accurately. - No silent handling: Catching a custom exception should not simply discard the error; the program should correct, report, or propagate it.
V. Text file read/write operations — persistent character data
Text file handling transfers character data between a Python program and a file stored on a device. The standard open() function creates a file object connected to a path.
A. Opening and closing text files
Opening a file requires a path and commonly a mode; encoding should be stated when text portability matters.
- Path:
"notes.txt"identifies the file; a relative path depends on the program’s current working directory. - Modes:
rreads an existing file.wwrites and truncates an existing file or creates a new file.aappends to the end or creates the file.xcreates a new file and fails if it already exists.
- Encoding:
encoding="utf-8"specifies how characters become bytes and back again. - Automatic closure:
with open(...) as file:closes the file after the block.
with open("greeting.txt", "w", encoding="utf-8") as file:
file.write("Hello, Python!\n")The string written contains a newline character, and the file is closed automatically.
B. Reading text
Reading methods differ in how much content they return and how they represent line boundaries.
read(): Returns the entire remaining file as one string;file.read(5)returns at most five characters.readline(): Returns one line, usually including its trailing newline.readlines(): Returns a list containing the remaining lines.- Iteration:
for line in fileprocesses one line at a time and is more memory-efficient for large files. - Whitespace:
line.strip()removes leading and trailing whitespace, including the newline; use it only when that removal is intended.
with open("scores.txt", "r", encoding="utf-8") as file:
for line in file:
print(line.strip())C. Writing and appending text
Writing methods place strings into a file; they do not automatically convert arbitrary objects into text.
write(): Writes one string and returns the number of characters written;file.write("A\n")writes two characters.writelines(): Writes an iterable of strings without adding separators, so each item should contain its own\nwhen line breaks are required.- Conversion:
file.write(str(25))is valid, whereasfile.write(25)raisesTypeError. - Truncation risk: Mode
werases previous content before writing; modeapreserves it and adds new content. - Error handling: Opening a missing file in
rmode raisesFileNotFoundError; an unavailable location may raisePermissionError.
D. File handling applications and limitations
Text files are simple and human-readable, but their structure must be designed and interpreted consistently.
- Applications: Logs, configuration fragments, reports, and line-based records can be stored as text.
- Newline handling:
newlinebehavior can differ across operating systems; normal text mode generally translates line endings appropriately. - Large files: Iteration avoids loading the entire file into memory, unlike
read(). - Atomicity limitation: A program interrupted during a rewrite may leave incomplete content; temporary-file replacement is safer for critical data.
- Security: Never treat file contents as trusted input; validate data before using it.
VI. Reading JSON files — structured data exchange
JSON, or JavaScript Object Notation, is a text format for representing structured values. Python’s json module converts between JSON text and Python objects.
A. JSON structure and Python mapping
JSON supports a limited set of data types that map directly to Python values.
- Object mapping: A JSON object such as
{"name": "Mira", "age": 20}becomes a Pythondict. - Array mapping: A JSON array such as
[10, 20, 30]becomes a Pythonlist. - Primitive mapping: JSON strings become
str, numbers becomeintorfloat,trueandfalsebecomeTrueandFalse, andnullbecomesNone. - Restriction: JSON object keys must be strings; Python dictionaries with non-string keys may not round-trip as expected.
- Validity: JSON requires valid syntax, including double-quoted strings and correctly matched brackets.
B. json.load() and file reading
json.load() reads JSON directly from an open text file and returns the corresponding Python object.
- Opening: Use read mode and UTF-8 encoding for a JSON text file.
- Conversion:
json.load(file)parses the complete file, so the resulting value may be a dictionary, list, string, number, Boolean, orNone. - Failures: Missing files raise
FileNotFoundError; invalid JSON raisesjson.JSONDecodeError. - Validation: Parsing confirms JSON syntax, not that required application fields or value ranges are correct.
import json
try:
with open("student.json", "r", encoding="utf-8") as file:
student = json.load(file)
print(student["name"])
except FileNotFoundError:
print("The JSON file is missing")
except json.JSONDecodeError:
print("The JSON syntax is invalid")C. Processing and limitations
Reading JSON is useful when programs need named, nested, and portable data, but parsed data must still be checked.
- Field access:
student["name"]requires the"name"key; a missing key raisesKeyError. - Safer lookup:
student.get("grade")returnsNoneby default when"grade"is absent. - Type validation: Confirm that
studentis a dictionary and thatstudent["age"]is numeric before calculations. - Memory limitation:
json.load()normally builds the entire structure in memory; very large datasets may require streaming formats or incremental processing. - Trust boundary: JSON parsing does not make data safe; validate values and avoid assuming that external files follow the expected schema.
Did this save you a night before the exam?
LPU Notes is free, and it stays free. Ads cover part of the server bill. The rest comes out of a student's own pocket: the domain, the storage, and keeping the site up through the weeks everyone needs it at once.
The payment button didn't load. An ad blocker or a filtered network is the usual reason. to try again.
Nothing here is ever locked, and nothing unlocks. Chip in only if it was worth it. What it pays for →