Day 10 – Exception Handling and Debugging
🐞 Day 10 – Exception Handling and Debugging
1. Learning Objectives
By the end of Day 10, you will be able to:
- Use
try/except/else/finallyblocks to handle runtime errors gracefully. - Handle specific exception types (
FileNotFoundError,ValueError,ZeroDivisionError,KeyError). - Write robust code that doesn’t crash on messy input data or missing files.
- Use basic debugging techniques:
print()debugging, reading tracebacks, and usingpdb. - Apply exception handling to real AEC scenarios (missing spreadsheet cells, division by zero in calculations, file import errors).
2. Concept Explanation
2.1 What Are Exceptions?
Exceptions are errors that occur during program execution. When an exception is not handled, the program crashes with a traceback. Common AEC exceptions:
| Exception | Common Cause in AEC |
|---|---|
FileNotFoundError | Trying to open a CSV/Excel file that doesn’t exist |
ValueError | User enters text where a number is expected |
ZeroDivisionError | Dividing by zero (e.g., span = 0 in moment calc) |
KeyError | Accessing a dictionary key that doesn’t exist |
IndexError | Accessing a list index out of range |
TypeError | Adding a string and number without casting |
2.2 The try/except/else/finally Structure
try:
# Code that might raise an exception
risky_operation()
except SomeExceptionType as e:
# Code to handle the error
print(f"Error occurred: {e}")
else:
# Code that runs if no exception occurred (optional)
print("Operation succeeded!")
finally:
# Code that always runs, even if exception occurs (optional)
cleanup_action()
2.3 Catching Multiple Exceptions
try:
value = float(input("Enter a number: "))
result = 100 / value
print(f"Result: {result}")
except ValueError:
print("Please enter a valid number.")
except ZeroDivisionError:
print("Cannot divide by zero.")
except Exception as e:
print(f"Unexpected error: {e}")
2.4 Raising Your Own Exceptions
You can raise exceptions to signal invalid conditions:
def calculate_stress(force, area):
if area <= 0:
raise ValueError("Area must be positive")
return force / area
2.5 Debugging Basics
print()debugging: Insert print statements to inspect variable values.- Reading tracebacks: The error message tells you the file, line number, and type of error.
- Using
pdb(Python Debugger): Insertimport pdb; pdb.set_trace()to pause execution and inspect interactively.
3. Code Examples
Example 1: Robust user input for a beam span
def get_positive_float(prompt):
"""Safely get a positive float from user input."""
while True:
try:
value = float(input(prompt))
if value <= 0:
print("Value must be positive. Try again.")
continue
return value
except ValueError:
print("Invalid input. Please enter a number.")
# Usage
span = get_positive_float("Enter beam span (m): ")
print(f"Span: {span:.2f} m")
Example 2: Safe file reading with error handling
def read_member_schedule(filename):
"""Read a CSV member schedule with error handling."""
import csv
members = []
try:
with open(filename, "r") as f:
reader = csv.DictReader(f)
for row in reader:
try:
member = {
"id": row["Member"],
"span": float(row["Span_m"]),
"load": float(row["Load_kNm"]),
}
members.append(member)
except (ValueError, KeyError) as e:
print(f"Skipping invalid row: {row} – {e}")
except FileNotFoundError:
print(f"ERROR: File '{filename}' not found.")
return []
except Exception as e:
print(f"Unexpected error reading file: {e}")
return []
else:
print(f"Successfully read {len(members)} members from {filename}")
return members
# Test
data = read_member_schedule("beams.csv")
if data:
print(f"Loaded {len(data)} beams.")
Example 3: Handling division by zero in stress calculations
def calculate_bending_stress(moment, section_modulus):
"""
Calculate bending stress = M / S.
Returns None if section_modulus is zero to avoid division error.
"""
try:
stress = moment / section_modulus
return stress
except ZeroDivisionError:
print("WARNING: Section modulus is zero. Cannot compute stress.")
return None
# Test cases
print(calculate_bending_stress(100000, 500)) # 200.0
print(calculate_bending_stress(100000, 0)) # Warning, returns None
Example 4: Using else and finally
def process_design_data():
file = None
try:
file = open("design_data.txt", "r")
content = file.read()
# ... process data ...
print("Data processed successfully.")
except FileNotFoundError:
print("Design data file missing.")
except Exception as e:
print(f"Processing error: {e}")
else:
print("No errors occurred during processing.")
finally:
if file:
file.close()
print("File closed.")
process_design_data()
Example 5: Debugging with print() and traceback
# Problematic code snippet
def compute_deflection(load, span, E, I):
print(f"DEBUG: load={load}, span={span}, E={E}, I={I}")
w = load * 1000 # N/m
L = span * 1000 # mm
deflection = 5 * w * L**4 / (384 * E * I)
return deflection
# This will raise an error if I is zero
try:
d = compute_deflection(20, 6, 200000, 0)
print(f"Deflection: {d:.2f} mm")
except ZeroDivisionError as e:
print(f"Calculation failed: {e}. Check moment of inertia value.")
4. Hands‑on Exercises (3–5 Problems)
Problem 1 – Safe integer input
Write a function safe_int_input(prompt) that keeps asking until the user enters a valid integer. Use try/except to catch ValueError.
Problem 2 – File reading with fallback
Write a script that tries to open design_data.csv. If the file doesn’t exist, print a friendly message and create an empty file with headers "Item, Value". Handle both FileNotFoundError and other exceptions.
Problem 3 – Divide two numbers from user input
Ask the user for two numbers (numerator and denominator). Use exception handling for:
ValueError(non-numeric input)ZeroDivisionError(denominator zero)
Print the result or an appropriate error message.
Problem 4 – Dictionary lookup with KeyError handling
You have a dictionary of material densities:densities = {"Steel": 7850, "Concrete": 2400, "Aluminium": 2700}
Ask the user for a material name. Use try/except to safely look up the density. If the material is not found, print a default message.
Solutions (attempt first):
# P1
def safe_int_input(prompt):
while True:
try:
return int(input(prompt))
except ValueError:
print("Invalid input. Please enter a whole number.")
age = safe_int_input("Enter floor count: ")
# P2
try:
with open("design_data.csv", "r") as f:
print("File found. Contents:")
print(f.read())
except FileNotFoundError:
print("design_data.csv not found. Creating a new file.")
with open("design_data.csv", "w") as f:
f.write("Item, Value\n")
except Exception as e:
print(f"Unexpected error: {e}")
# P3
try:
num = float(input("Numerator: "))
den = float(input("Denominator: "))
result = num / den
print(f"Result: {result:.2f}")
except ValueError:
print("Please enter numbers only.")
except ZeroDivisionError:
print("Cannot divide by zero.")
# P4
densities = {"Steel": 7850, "Concrete": 2400, "Aluminium": 2700}
material = input("Enter material: ").strip().title()
try:
density = densities[material]
print(f"Density of {material}: {density} kg/m³")
except KeyError:
print(f"Material '{material}' not found in database.")
5. Applied Challenge Task
Task: Robust Construction Data Importer
You are given a CSV file site_measurements.csv with the following structure (but it may contain errors):
Element, Length_m, Width_m, Height_m, Material
Beam1, 6.0, 0.3, 0.5, Concrete
Column1, 0.4, 0.4, 3.5, Steel
Slab1, 8.0, 5.0, , Concrete # missing height
Beam2, seven, 0.3, 0.5, Timber # non-numeric length
Column2, 0.5, 0.5, 3.0, # missing material
Write a script that:
Reads the CSV file using
csv.DictReaderinside atry/exceptblock.For each row, attempts to:
- Convert
Length_m,Width_m,Height_mto floats. - Check that
Materialis not empty.
- Convert
If a row has errors, catch the specific exception (
ValueError,KeyError), print a warning with the row number and the error, but continue processing the next rows.For valid rows, compute the volume and store the element in a list of dictionaries.
At the end, print:
- Total number of rows processed.
- Number of valid elements.
- Number of rows with errors.
- Total volume of all valid elements.
Write a clean CSV file
validated_elements.csvwith only the valid rows, including a calculatedVolume_m3column.
Why this matters:
In real AEC projects, imported data is almost never clean. This task trains you to write scripts that handle real‑world messiness gracefully – a critical skill for production‑ready tools.
6. Brief Review Summary
try/exceptprevents crashes from expected errors (file not found, bad input, division by zero).- Catch specific exceptions (
ValueError,FileNotFoundError) rather than a bareexcept. elseruns if no exception;finallyalways runs (cleanup).- Use
print()debugging to inspect values; read tracebacks carefully. - Raising your own exceptions (
raise ValueError(...)) signals invalid conditions.
Key takeaway:
Exception handling makes your scripts robust and professional. In AEC, where data is often messy and inputs unpredictable, handling errors gracefully is essential for trust and reliability.
7. Preview of Next Topic (Day 11)
Tomorrow we’ll cover List Comprehensions, Lambda, map/filter.
You’ll learn:
- Writing concise list comprehensions (e.g.,
[s for s in spans if s > 6]). - Anonymous functions with
lambda. - Using
map()andfilter()for functional‑style processing. - Practical AEC examples: filtering beams longer than 6m, converting all lengths to mm, extracting unique material names.
These techniques will make your code more expressive and efficient for data‑processing tasks.

Comments
Post a Comment