Exceptions
Try-Except
Handling Exceptions
Your program divides user input. If they enter zero, it crashes. Try-except lets you catch the error and respond gracefully - show a message, ask again, or use a default value. Your program keeps running.
Basic try-except
Catch and handle an exception.
# Basic try-except for division by zero
def main():
# Without exception handling (crashes)
print("Without try-except:")
# This would crash: result = 10 / 0
# With exception handling
print("\nWith try-except:")
try:
result = 10 / 0
print(f"Result: {result}")
except ZeroDivisionError:
print("Error: Cannot divide by zero")
result = None
print(f"Program continues, result = {result}")
# Safe division function
print("\nSafe division:")
numerator =
denominator =
try:
answer = numerator / denominator
print(f"{numerator} / {denominator} = {answer}")
except ZeroDivisionError:
print("Cannot divide by zero")
answer = 0
# Another example with zero
print("\nWith zero denominator:")
a = 15
b = 0
try:
quotient = a / b
print(f"{a} / {b} = {quotient}")
except ZeroDivisionError:
print(f"Cannot divide {a} by zero, using default value")
quotient = float('inf') # infinity
print(f"Final quotient: {quotient}")
if __name__ == "__main__":
main()
# Basic try-except for division by zero
def main():
# Without exception handling (crashes)
print("Without try-except:")
# This would crash: result = 10 / 0
# With exception handling
print("\nWith try-except:")
try:
result = 10 / 0
print(f"Result: {result}")
except ZeroDivisionError:
print("Error: Cannot divide by zero")
result = None
print(f"Program continues, result = {result}")
# Safe division function
print("\nSafe division:")
numerator =
denominator =
try:
answer = numerator / denominator
print(f"{numerator} / {denominator} = {answer}")
except ZeroDivisionError:
print("Cannot divide by zero")
answer = 0
# Another example with zero
print("\nWith zero denominator:")
a = 15
b = 0
try:
quotient = a / b
print(f"{a} / {b} = {quotient}")
except ZeroDivisionError:
print(f"Cannot divide {a} by zero, using default value")
quotient = float('inf') # infinity
print(f"Final quotient: {quotient}")
if __name__ == "__main__":
main()
# Basic try-except for division by zero
def main():
# Without exception handling (crashes)
print("Without try-except:")
# This would crash: result = 10 / 0
# With exception handling
print("\nWith try-except:")
try:
result = 10 / 0
print(f"Result: {result}")
except ZeroDivisionError:
print("Error: Cannot divide by zero")
result = None
print(f"Program continues, result = {result}")
# Safe division function
print("\nSafe division:")
numerator =
denominator =
try:
answer = numerator / denominator
print(f"{numerator} / {denominator} = {answer}")
except ZeroDivisionError:
print("Cannot divide by zero")
answer = 0
# Another example with zero
print("\nWith zero denominator:")
a = 15
b = 0
try:
quotient = a / b
print(f"{a} / {b} = {quotient}")
except ZeroDivisionError:
print(f"Cannot divide {a} by zero, using default value")
quotient = float('inf') # infinity
print(f"Final quotient: {quotient}")
if __name__ == "__main__":
main()
# Basic try-except for division by zero
def main():
# Without exception handling (crashes)
print("Without try-except:")
# This would crash: result = 10 / 0
# With exception handling
print("\nWith try-except:")
try:
result = 10 / 0
print(f"Result: {result}")
except ZeroDivisionError:
print("Error: Cannot divide by zero")
result = None
print(f"Program continues, result = {result}")
# Safe division function
print("\nSafe division:")
numerator =
denominator =
try:
answer = numerator / denominator
print(f"{numerator} / {denominator} = {answer}")
except ZeroDivisionError:
print("Cannot divide by zero")
answer = 0
# Another example with zero
print("\nWith zero denominator:")
a = 15
b = 0
try:
quotient = a / b
print(f"{a} / {b} = {quotient}")
except ZeroDivisionError:
print(f"Cannot divide {a} by zero, using default value")
quotient = float('inf') # infinity
print(f"Final quotient: {quotient}")
if __name__ == "__main__":
main()
# Basic try-except for division by zero
def main():
# Without exception handling (crashes)
print("Without try-except:")
# This would crash: result = 10 / 0
# With exception handling
print("\nWith try-except:")
try:
result = 10 / 0
print(f"Result: {result}")
except ZeroDivisionError:
print("Error: Cannot divide by zero")
result = None
print(f"Program continues, result = {result}")
# Safe division function
print("\nSafe division:")
numerator =
denominator =
try:
answer = numerator / denominator
print(f"{numerator} / {denominator} = {answer}")
except ZeroDivisionError:
print("Cannot divide by zero")
answer = 0
# Another example with zero
print("\nWith zero denominator:")
a = 15
b = 0
try:
quotient = a / b
print(f"{a} / {b} = {quotient}")
except ZeroDivisionError:
print(f"Cannot divide {a} by zero, using default value")
quotient = float('inf') # infinity
print(f"Final quotient: {quotient}")
if __name__ == "__main__":
main()
# Basic try-except for division by zero
def main():
# Without exception handling (crashes)
print("Without try-except:")
# This would crash: result = 10 / 0
# With exception handling
print("\nWith try-except:")
try:
result = 10 / 0
print(f"Result: {result}")
except ZeroDivisionError:
print("Error: Cannot divide by zero")
result = None
print(f"Program continues, result = {result}")
# Safe division function
print("\nSafe division:")
numerator =
denominator =
try:
answer = numerator / denominator
print(f"{numerator} / {denominator} = {answer}")
except ZeroDivisionError:
print("Cannot divide by zero")
answer = 0
# Another example with zero
print("\nWith zero denominator:")
a = 15
b = 0
try:
quotient = a / b
print(f"{a} / {b} = {quotient}")
except ZeroDivisionError:
print(f"Cannot divide {a} by zero, using default value")
quotient = float('inf') # infinity
print(f"Final quotient: {quotient}")
if __name__ == "__main__":
main()
# Basic try-except for division by zero
def main():
# Without exception handling (crashes)
print("Without try-except:")
# This would crash: result = 10 / 0
# With exception handling
print("\nWith try-except:")
try:
result = 10 / 0
print(f"Result: {result}")
except ZeroDivisionError:
print("Error: Cannot divide by zero")
result = None
print(f"Program continues, result = {result}")
# Safe division function
print("\nSafe division:")
numerator =
denominator =
try:
answer = numerator / denominator
print(f"{numerator} / {denominator} = {answer}")
except ZeroDivisionError:
print("Cannot divide by zero")
answer = 0
# Another example with zero
print("\nWith zero denominator:")
a = 15
b = 0
try:
quotient = a / b
print(f"{a} / {b} = {quotient}")
except ZeroDivisionError:
print(f"Cannot divide {a} by zero, using default value")
quotient = float('inf') # infinity
print(f"Final quotient: {quotient}")
if __name__ == "__main__":
main()
# Basic try-except for division by zero
def main():
# Without exception handling (crashes)
print("Without try-except:")
# This would crash: result = 10 / 0
# With exception handling
print("\nWith try-except:")
try:
result = 10 / 0
print(f"Result: {result}")
except ZeroDivisionError:
print("Error: Cannot divide by zero")
result = None
print(f"Program continues, result = {result}")
# Safe division function
print("\nSafe division:")
numerator =
denominator =
try:
answer = numerator / denominator
print(f"{numerator} / {denominator} = {answer}")
except ZeroDivisionError:
print("Cannot divide by zero")
answer = 0
# Another example with zero
print("\nWith zero denominator:")
a = 15
b = 0
try:
quotient = a / b
print(f"{a} / {b} = {quotient}")
except ZeroDivisionError:
print(f"Cannot divide {a} by zero, using default value")
quotient = float('inf') # infinity
print(f"Final quotient: {quotient}")
if __name__ == "__main__":
main()
# Basic try-except for division by zero
def main():
# Without exception handling (crashes)
print("Without try-except:")
# This would crash: result = 10 / 0
# With exception handling
print("\nWith try-except:")
try:
result = 10 / 0
print(f"Result: {result}")
except ZeroDivisionError:
print("Error: Cannot divide by zero")
result = None
print(f"Program continues, result = {result}")
# Safe division function
print("\nSafe division:")
numerator =
denominator =
try:
answer = numerator / denominator
print(f"{numerator} / {denominator} = {answer}")
except ZeroDivisionError:
print("Cannot divide by zero")
answer = 0
# Another example with zero
print("\nWith zero denominator:")
a = 15
b = 0
try:
quotient = a / b
print(f"{a} / {b} = {quotient}")
except ZeroDivisionError:
print(f"Cannot divide {a} by zero, using default value")
quotient = float('inf') # infinity
print(f"Final quotient: {quotient}")
if __name__ == "__main__":
main()
# Basic try-except for division by zero
def main():
# Without exception handling (crashes)
print("Without try-except:")
# This would crash: result = 10 / 0
# With exception handling
print("\nWith try-except:")
try:
result = 10 / 0
print(f"Result: {result}")
except ZeroDivisionError:
print("Error: Cannot divide by zero")
result = None
print(f"Program continues, result = {result}")
# Safe division function
print("\nSafe division:")
numerator =
denominator =
try:
answer = numerator / denominator
print(f"{numerator} / {denominator} = {answer}")
except ZeroDivisionError:
print("Cannot divide by zero")
answer = 0
# Another example with zero
print("\nWith zero denominator:")
a = 15
b = 0
try:
quotient = a / b
print(f"{a} / {b} = {quotient}")
except ZeroDivisionError:
print(f"Cannot divide {a} by zero, using default value")
quotient = float('inf') # infinity
print(f"Final quotient: {quotient}")
if __name__ == "__main__":
main()
# Basic try-except for division by zero
def main():
# Without exception handling (crashes)
print("Without try-except:")
# This would crash: result = 10 / 0
# With exception handling
print("\nWith try-except:")
try:
result = 10 / 0
print(f"Result: {result}")
except ZeroDivisionError:
print("Error: Cannot divide by zero")
result = None
print(f"Program continues, result = {result}")
# Safe division function
print("\nSafe division:")
numerator =
denominator =
try:
answer = numerator / denominator
print(f"{numerator} / {denominator} = {answer}")
except ZeroDivisionError:
print("Cannot divide by zero")
answer = 0
# Another example with zero
print("\nWith zero denominator:")
a = 15
b = 0
try:
quotient = a / b
print(f"{a} / {b} = {quotient}")
except ZeroDivisionError:
print(f"Cannot divide {a} by zero, using default value")
quotient = float('inf') # infinity
print(f"Final quotient: {quotient}")
if __name__ == "__main__":
main()
# Basic try-except for division by zero
def main():
# Without exception handling (crashes)
print("Without try-except:")
# This would crash: result = 10 / 0
# With exception handling
print("\nWith try-except:")
try:
result = 10 / 0
print(f"Result: {result}")
except ZeroDivisionError:
print("Error: Cannot divide by zero")
result = None
print(f"Program continues, result = {result}")
# Safe division function
print("\nSafe division:")
numerator =
denominator =
try:
answer = numerator / denominator
print(f"{numerator} / {denominator} = {answer}")
except ZeroDivisionError:
print("Cannot divide by zero")
answer = 0
# Another example with zero
print("\nWith zero denominator:")
a = 15
b = 0
try:
quotient = a / b
print(f"{a} / {b} = {quotient}")
except ZeroDivisionError:
print(f"Cannot divide {a} by zero, using default value")
quotient = float('inf') # infinity
print(f"Final quotient: {quotient}")
if __name__ == "__main__":
main()
# Basic try-except for division by zero
def main():
# Without exception handling (crashes)
print("Without try-except:")
# This would crash: result = 10 / 0
# With exception handling
print("\nWith try-except:")
try:
result = 10 / 0
print(f"Result: {result}")
except ZeroDivisionError:
print("Error: Cannot divide by zero")
result = None
print(f"Program continues, result = {result}")
# Safe division function
print("\nSafe division:")
numerator =
denominator =
try:
answer = numerator / denominator
print(f"{numerator} / {denominator} = {answer}")
except ZeroDivisionError:
print("Cannot divide by zero")
answer = 0
# Another example with zero
print("\nWith zero denominator:")
a = 15
b = 0
try:
quotient = a / b
print(f"{a} / {b} = {quotient}")
except ZeroDivisionError:
print(f"Cannot divide {a} by zero, using default value")
quotient = float('inf') # infinity
print(f"Final quotient: {quotient}")
if __name__ == "__main__":
main()
# Basic try-except for division by zero
def main():
# Without exception handling (crashes)
print("Without try-except:")
# This would crash: result = 10 / 0
# With exception handling
print("\nWith try-except:")
try:
result = 10 / 0
print(f"Result: {result}")
except ZeroDivisionError:
print("Error: Cannot divide by zero")
result = None
print(f"Program continues, result = {result}")
# Safe division function
print("\nSafe division:")
numerator =
denominator =
try:
answer = numerator / denominator
print(f"{numerator} / {denominator} = {answer}")
except ZeroDivisionError:
print("Cannot divide by zero")
answer = 0
# Another example with zero
print("\nWith zero denominator:")
a = 15
b = 0
try:
quotient = a / b
print(f"{a} / {b} = {quotient}")
except ZeroDivisionError:
print(f"Cannot divide {a} by zero, using default value")
quotient = float('inf') # infinity
print(f"Final quotient: {quotient}")
if __name__ == "__main__":
main()
# Basic try-except for division by zero
def main():
# Without exception handling (crashes)
print("Without try-except:")
# This would crash: result = 10 / 0
# With exception handling
print("\nWith try-except:")
try:
result = 10 / 0
print(f"Result: {result}")
except ZeroDivisionError:
print("Error: Cannot divide by zero")
result = None
print(f"Program continues, result = {result}")
# Safe division function
print("\nSafe division:")
numerator =
denominator =
try:
answer = numerator / denominator
print(f"{numerator} / {denominator} = {answer}")
except ZeroDivisionError:
print("Cannot divide by zero")
answer = 0
# Another example with zero
print("\nWith zero denominator:")
a = 15
b = 0
try:
quotient = a / b
print(f"{a} / {b} = {quotient}")
except ZeroDivisionError:
print(f"Cannot divide {a} by zero, using default value")
quotient = float('inf') # infinity
print(f"Final quotient: {quotient}")
if __name__ == "__main__":
main()
# Basic try-except for division by zero
def main():
# Without exception handling (crashes)
print("Without try-except:")
# This would crash: result = 10 / 0
# With exception handling
print("\nWith try-except:")
try:
result = 10 / 0
print(f"Result: {result}")
except ZeroDivisionError:
print("Error: Cannot divide by zero")
result = None
print(f"Program continues, result = {result}")
# Safe division function
print("\nSafe division:")
numerator =
denominator =
try:
answer = numerator / denominator
print(f"{numerator} / {denominator} = {answer}")
except ZeroDivisionError:
print("Cannot divide by zero")
answer = 0
# Another example with zero
print("\nWith zero denominator:")
a = 15
b = 0
try:
quotient = a / b
print(f"{a} / {b} = {quotient}")
except ZeroDivisionError:
print(f"Cannot divide {a} by zero, using default value")
quotient = float('inf') # infinity
print(f"Final quotient: {quotient}")
if __name__ == "__main__":
main()
Code that might fail goes in try. Error handling goes in except.
Catch index errors
Handle accessing invalid list indices.
# Catching IndexError when accessing list elements
def main():
# Safe list access
scores =
print("Scores:", scores)
print(f"Total scores: {len(scores)}")
# Access valid index
try:
first = scores[0]
print(f"\nFirst score: {first}")
except IndexError:
print("Index out of range")
first = None
# Access invalid index
print("\nAccessing index 10:")
try:
value = scores[10]
print(f"Value: {value}")
except IndexError:
print("Error: Index 10 doesn't exist")
value = None
# Safe get function
def safe_get(lst, index, default=0):
try:
return lst[index]
except IndexError:
return default
print("\nUsing safe_get:")
print(f"Index 2: {safe_get(scores, 2)}")
print(f"Index 99: {safe_get(scores, 99, default=-1)}")
# Multiple attempts
indices = [0, 2, 5, 3, 10]
print("\nAccessing multiple indices:")
for i in indices:
try:
score = scores[i]
print(f" scores[{i}] = {score}")
except IndexError:
print(f" scores[{i}] = OUT OF RANGE")
if __name__ == "__main__":
main()
# Catching IndexError when accessing list elements
def main():
# Safe list access
scores =
print("Scores:", scores)
print(f"Total scores: {len(scores)}")
# Access valid index
try:
first = scores[0]
print(f"\nFirst score: {first}")
except IndexError:
print("Index out of range")
first = None
# Access invalid index
print("\nAccessing index 10:")
try:
value = scores[10]
print(f"Value: {value}")
except IndexError:
print("Error: Index 10 doesn't exist")
value = None
# Safe get function
def safe_get(lst, index, default=0):
try:
return lst[index]
except IndexError:
return default
print("\nUsing safe_get:")
print(f"Index 2: {safe_get(scores, 2)}")
print(f"Index 99: {safe_get(scores, 99, default=-1)}")
# Multiple attempts
indices = [0, 2, 5, 3, 10]
print("\nAccessing multiple indices:")
for i in indices:
try:
score = scores[i]
print(f" scores[{i}] = {score}")
except IndexError:
print(f" scores[{i}] = OUT OF RANGE")
if __name__ == "__main__":
main()
# Catching IndexError when accessing list elements
def main():
# Safe list access
scores =
print("Scores:", scores)
print(f"Total scores: {len(scores)}")
# Access valid index
try:
first = scores[0]
print(f"\nFirst score: {first}")
except IndexError:
print("Index out of range")
first = None
# Access invalid index
print("\nAccessing index 10:")
try:
value = scores[10]
print(f"Value: {value}")
except IndexError:
print("Error: Index 10 doesn't exist")
value = None
# Safe get function
def safe_get(lst, index, default=0):
try:
return lst[index]
except IndexError:
return default
print("\nUsing safe_get:")
print(f"Index 2: {safe_get(scores, 2)}")
print(f"Index 99: {safe_get(scores, 99, default=-1)}")
# Multiple attempts
indices = [0, 2, 5, 3, 10]
print("\nAccessing multiple indices:")
for i in indices:
try:
score = scores[i]
print(f" scores[{i}] = {score}")
except IndexError:
print(f" scores[{i}] = OUT OF RANGE")
if __name__ == "__main__":
main()
IndexError when accessing index outside list range.
Multiple except blocks
Handle different exceptions differently.
# Multiple except blocks for different errors
def main():
# Parse user input (multiple error types)
print("Input parsing with multiple exceptions:\n")
data = {
"name": "Alice",
"age": "25",
"scores": [85, 90, 78]
}
# Catch ValueError (bad conversion)
try:
age_str =
age = int(age_str)
print(f"Age: {age}")
except ValueError:
print("ValueError: Cannot convert to integer")
age = 0
# Catch KeyError (missing key)
try:
email = data["email"] # key doesn't exist
print(f"Email: {email}")
except KeyError:
print("KeyError: 'email' key not found")
email = "unknown@example.com"
# Multiple exceptions in one try block
print("\nProcessing with multiple potential errors:")
try:
# Could raise KeyError
score_str = data["score"] # missing key
# Could raise ValueError
score = int(score_str)
# Could raise IndexError
first_score = data["scores"][10]
print(f"Score: {score}, First: {first_score}")
except KeyError as e:
print(f"Missing key: {e}")
except ValueError as e:
print(f"Invalid value: {e}")
except IndexError as e:
print(f"Index error: {e}")
# Catch parent exception
print("\nUsing generic Exception:")
try:
result = data["count"] / 0
except ZeroDivisionError:
print("Specific: Division by zero")
except Exception as e:
print(f"Generic: {type(e).__name__}: {e}")
# Process list of operations
operations = [
("parse", "123"),
("parse", "abc"),
("divide", 10, 0),
("access", [1, 2], 5)
]
print("\nProcessing operations:")
for op in operations:
try:
if op[0] == "parse":
result = int(op[1])
print(f" Parsed: {result}")
elif op[0] == "divide":
result = op[1] / op[2]
print(f" Divided: {result}")
elif op[0] == "access":
result = op[1][op[2]]
print(f" Accessed: {result}")
except ValueError:
print(f" ValueError in {op}")
except ZeroDivisionError:
print(f" ZeroDivisionError in {op}")
except IndexError:
print(f" IndexError in {op}")
if __name__ == "__main__":
main()
# Multiple except blocks for different errors
def main():
# Parse user input (multiple error types)
print("Input parsing with multiple exceptions:\n")
data = {
"name": "Alice",
"age": "25",
"scores": [85, 90, 78]
}
# Catch ValueError (bad conversion)
try:
age_str =
age = int(age_str)
print(f"Age: {age}")
except ValueError:
print("ValueError: Cannot convert to integer")
age = 0
# Catch KeyError (missing key)
try:
email = data["email"] # key doesn't exist
print(f"Email: {email}")
except KeyError:
print("KeyError: 'email' key not found")
email = "unknown@example.com"
# Multiple exceptions in one try block
print("\nProcessing with multiple potential errors:")
try:
# Could raise KeyError
score_str = data["score"] # missing key
# Could raise ValueError
score = int(score_str)
# Could raise IndexError
first_score = data["scores"][10]
print(f"Score: {score}, First: {first_score}")
except KeyError as e:
print(f"Missing key: {e}")
except ValueError as e:
print(f"Invalid value: {e}")
except IndexError as e:
print(f"Index error: {e}")
# Catch parent exception
print("\nUsing generic Exception:")
try:
result = data["count"] / 0
except ZeroDivisionError:
print("Specific: Division by zero")
except Exception as e:
print(f"Generic: {type(e).__name__}: {e}")
# Process list of operations
operations = [
("parse", "123"),
("parse", "abc"),
("divide", 10, 0),
("access", [1, 2], 5)
]
print("\nProcessing operations:")
for op in operations:
try:
if op[0] == "parse":
result = int(op[1])
print(f" Parsed: {result}")
elif op[0] == "divide":
result = op[1] / op[2]
print(f" Divided: {result}")
elif op[0] == "access":
result = op[1][op[2]]
print(f" Accessed: {result}")
except ValueError:
print(f" ValueError in {op}")
except ZeroDivisionError:
print(f" ZeroDivisionError in {op}")
except IndexError:
print(f" IndexError in {op}")
if __name__ == "__main__":
main()
# Multiple except blocks for different errors
def main():
# Parse user input (multiple error types)
print("Input parsing with multiple exceptions:\n")
data = {
"name": "Alice",
"age": "25",
"scores": [85, 90, 78]
}
# Catch ValueError (bad conversion)
try:
age_str =
age = int(age_str)
print(f"Age: {age}")
except ValueError:
print("ValueError: Cannot convert to integer")
age = 0
# Catch KeyError (missing key)
try:
email = data["email"] # key doesn't exist
print(f"Email: {email}")
except KeyError:
print("KeyError: 'email' key not found")
email = "unknown@example.com"
# Multiple exceptions in one try block
print("\nProcessing with multiple potential errors:")
try:
# Could raise KeyError
score_str = data["score"] # missing key
# Could raise ValueError
score = int(score_str)
# Could raise IndexError
first_score = data["scores"][10]
print(f"Score: {score}, First: {first_score}")
except KeyError as e:
print(f"Missing key: {e}")
except ValueError as e:
print(f"Invalid value: {e}")
except IndexError as e:
print(f"Index error: {e}")
# Catch parent exception
print("\nUsing generic Exception:")
try:
result = data["count"] / 0
except ZeroDivisionError:
print("Specific: Division by zero")
except Exception as e:
print(f"Generic: {type(e).__name__}: {e}")
# Process list of operations
operations = [
("parse", "123"),
("parse", "abc"),
("divide", 10, 0),
("access", [1, 2], 5)
]
print("\nProcessing operations:")
for op in operations:
try:
if op[0] == "parse":
result = int(op[1])
print(f" Parsed: {result}")
elif op[0] == "divide":
result = op[1] / op[2]
print(f" Divided: {result}")
elif op[0] == "access":
result = op[1][op[2]]
print(f" Accessed: {result}")
except ValueError:
print(f" ValueError in {op}")
except ZeroDivisionError:
print(f" ZeroDivisionError in {op}")
except IndexError:
print(f" IndexError in {op}")
if __name__ == "__main__":
main()
Specific exceptions first, general Exception last. Order matters.
Catch parent exception
Catch parent type to handle all subtypes.
# Catching parent exception types
def main():
# Catch general Exception
print("Catching general Exception:\n")
numbers = [10, 20, 30]
try:
# Could be any type of error
index =
value = numbers[index]
result = value / 0
except Exception as e:
# Catches ANY exception
print(f"Caught: {type(e).__name__}")
print(f"Message: {e}")
# Specific vs general order matters
print("\nException handling order:")
data = {"x": "not_a_number"}
try:
num = int(data["y"])
except KeyError:
print("Specific: Missing key")
except ValueError:
print("Specific: Bad value")
except Exception as e:
print(f"General: {type(e).__name__}")
# Access exception details
print("\nException details:")
items = [1, 2, 3]
try:
value = items[10]
except Exception as e:
print(f"Type: {type(e).__name__}")
print(f"Message: {str(e)}")
print(f"Args: {e.args}")
# Multiple operations with general catch
def safe_operate(operation, a, b):
try:
if operation == "divide":
return a / b
elif operation == "get":
return a[b]
elif operation == "parse":
return int(a)
else:
return None
except Exception as e:
print(f" Error in {operation}: {type(e).__name__}")
return None
print("\nSafe operations:")
print(f"divide 10/2: {safe_operate('divide', 10, 2)}")
print(f"divide 10/0: {safe_operate('divide', 10, 0)}")
print(f"get [1,2,3][5]: {safe_operate('get', [1,2,3], 5)}")
print(f"parse 'abc': {safe_operate('parse', 'abc', None)}")
# Catch and re-raise pattern
print("\nLogging then re-raising:")
try:
try:
result = 100 / 0
except ZeroDivisionError as e:
print(f"Logging: {e}")
# Could log to file here
# Then let it propagate
except Exception:
print("Outer handler caught it")
if __name__ == "__main__":
main()
# Catching parent exception types
def main():
# Catch general Exception
print("Catching general Exception:\n")
numbers = [10, 20, 30]
try:
# Could be any type of error
index =
value = numbers[index]
result = value / 0
except Exception as e:
# Catches ANY exception
print(f"Caught: {type(e).__name__}")
print(f"Message: {e}")
# Specific vs general order matters
print("\nException handling order:")
data = {"x": "not_a_number"}
try:
num = int(data["y"])
except KeyError:
print("Specific: Missing key")
except ValueError:
print("Specific: Bad value")
except Exception as e:
print(f"General: {type(e).__name__}")
# Access exception details
print("\nException details:")
items = [1, 2, 3]
try:
value = items[10]
except Exception as e:
print(f"Type: {type(e).__name__}")
print(f"Message: {str(e)}")
print(f"Args: {e.args}")
# Multiple operations with general catch
def safe_operate(operation, a, b):
try:
if operation == "divide":
return a / b
elif operation == "get":
return a[b]
elif operation == "parse":
return int(a)
else:
return None
except Exception as e:
print(f" Error in {operation}: {type(e).__name__}")
return None
print("\nSafe operations:")
print(f"divide 10/2: {safe_operate('divide', 10, 2)}")
print(f"divide 10/0: {safe_operate('divide', 10, 0)}")
print(f"get [1,2,3][5]: {safe_operate('get', [1,2,3], 5)}")
print(f"parse 'abc': {safe_operate('parse', 'abc', None)}")
# Catch and re-raise pattern
print("\nLogging then re-raising:")
try:
try:
result = 100 / 0
except ZeroDivisionError as e:
print(f"Logging: {e}")
# Could log to file here
# Then let it propagate
except Exception:
print("Outer handler caught it")
if __name__ == "__main__":
main()
# Catching parent exception types
def main():
# Catch general Exception
print("Catching general Exception:\n")
numbers = [10, 20, 30]
try:
# Could be any type of error
index =
value = numbers[index]
result = value / 0
except Exception as e:
# Catches ANY exception
print(f"Caught: {type(e).__name__}")
print(f"Message: {e}")
# Specific vs general order matters
print("\nException handling order:")
data = {"x": "not_a_number"}
try:
num = int(data["y"])
except KeyError:
print("Specific: Missing key")
except ValueError:
print("Specific: Bad value")
except Exception as e:
print(f"General: {type(e).__name__}")
# Access exception details
print("\nException details:")
items = [1, 2, 3]
try:
value = items[10]
except Exception as e:
print(f"Type: {type(e).__name__}")
print(f"Message: {str(e)}")
print(f"Args: {e.args}")
# Multiple operations with general catch
def safe_operate(operation, a, b):
try:
if operation == "divide":
return a / b
elif operation == "get":
return a[b]
elif operation == "parse":
return int(a)
else:
return None
except Exception as e:
print(f" Error in {operation}: {type(e).__name__}")
return None
print("\nSafe operations:")
print(f"divide 10/2: {safe_operate('divide', 10, 2)}")
print(f"divide 10/0: {safe_operate('divide', 10, 0)}")
print(f"get [1,2,3][5]: {safe_operate('get', [1,2,3], 5)}")
print(f"parse 'abc': {safe_operate('parse', 'abc', None)}")
# Catch and re-raise pattern
print("\nLogging then re-raising:")
try:
try:
result = 100 / 0
except ZeroDivisionError as e:
print(f"Logging: {e}")
# Could log to file here
# Then let it propagate
except Exception:
print("Outer handler caught it")
if __name__ == "__main__":
main()
# Catching parent exception types
def main():
# Catch general Exception
print("Catching general Exception:\n")
numbers = [10, 20, 30]
try:
# Could be any type of error
index =
value = numbers[index]
result = value / 0
except Exception as e:
# Catches ANY exception
print(f"Caught: {type(e).__name__}")
print(f"Message: {e}")
# Specific vs general order matters
print("\nException handling order:")
data = {"x": "not_a_number"}
try:
num = int(data["y"])
except KeyError:
print("Specific: Missing key")
except ValueError:
print("Specific: Bad value")
except Exception as e:
print(f"General: {type(e).__name__}")
# Access exception details
print("\nException details:")
items = [1, 2, 3]
try:
value = items[10]
except Exception as e:
print(f"Type: {type(e).__name__}")
print(f"Message: {str(e)}")
print(f"Args: {e.args}")
# Multiple operations with general catch
def safe_operate(operation, a, b):
try:
if operation == "divide":
return a / b
elif operation == "get":
return a[b]
elif operation == "parse":
return int(a)
else:
return None
except Exception as e:
print(f" Error in {operation}: {type(e).__name__}")
return None
print("\nSafe operations:")
print(f"divide 10/2: {safe_operate('divide', 10, 2)}")
print(f"divide 10/0: {safe_operate('divide', 10, 0)}")
print(f"get [1,2,3][5]: {safe_operate('get', [1,2,3], 5)}")
print(f"parse 'abc': {safe_operate('parse', 'abc', None)}")
# Catch and re-raise pattern
print("\nLogging then re-raising:")
try:
try:
result = 100 / 0
except ZeroDivisionError as e:
print(f"Logging: {e}")
# Could log to file here
# Then let it propagate
except Exception:
print("Outer handler caught it")
if __name__ == "__main__":
main()
Catching Exception catches (almost) everything. Be specific when possible.
Finally block
Code that always runs, even after exception.
# Finally block for cleanup
def main():
# Finally always executes
print("Finally block basics:\n")
try:
print("In try block")
result = 10 / 2
print(f"Result: {result}")
except ZeroDivisionError:
print("In except block")
finally:
print("In finally block (always runs)")
# Finally runs even with exception
print("\nWith exception:")
try:
print("In try block")
result = 10 / 0 # raises error
print("This won't print")
except ZeroDivisionError:
print("In except block")
finally:
print("In finally block (runs despite error)")
# Simulated file handling
def process_file(filename):
file_handle = None
try:
print(f"\nOpening {filename}")
file_handle = f"<handle:{filename}>"
if "error" in filename:
raise ValueError("Simulated read error")
print(f"Processing {filename}")
return "SUCCESS"
except ValueError as e:
print(f"Error: {e}")
return "FAILED"
finally:
if file_handle:
print(f"Closing {file_handle}")
result1 = process_file("data.txt")
print(f"Result: {result1}")
result2 = process_file("error.txt")
print(f"Result: {result2}")
# Try-except-else-finally (complete form)
print("\nComplete form:")
value =
try:
num = int(value)
except ValueError:
print("Conversion failed")
num = 0
else:
# Runs only if NO exception
print(f"Conversion succeeded: {num}")
finally:
print("Cleanup complete")
# Resource tracking
class Resource:
def __init__(self, name):
self.name = name
print(f" Acquired: {name}")
def close(self):
print(f" Released: {self.name}")
print("\nResource management:")
resource = None
try:
resource = Resource("Database")
# Simulate work
items = [1, 2, 3]
value = items[5] # Error!
except IndexError:
print(" Error during processing")
finally:
if resource:
resource.close()
if __name__ == "__main__":
main()
# Finally block for cleanup
def main():
# Finally always executes
print("Finally block basics:\n")
try:
print("In try block")
result = 10 / 2
print(f"Result: {result}")
except ZeroDivisionError:
print("In except block")
finally:
print("In finally block (always runs)")
# Finally runs even with exception
print("\nWith exception:")
try:
print("In try block")
result = 10 / 0 # raises error
print("This won't print")
except ZeroDivisionError:
print("In except block")
finally:
print("In finally block (runs despite error)")
# Simulated file handling
def process_file(filename):
file_handle = None
try:
print(f"\nOpening {filename}")
file_handle = f"<handle:{filename}>"
if "error" in filename:
raise ValueError("Simulated read error")
print(f"Processing {filename}")
return "SUCCESS"
except ValueError as e:
print(f"Error: {e}")
return "FAILED"
finally:
if file_handle:
print(f"Closing {file_handle}")
result1 = process_file("data.txt")
print(f"Result: {result1}")
result2 = process_file("error.txt")
print(f"Result: {result2}")
# Try-except-else-finally (complete form)
print("\nComplete form:")
value =
try:
num = int(value)
except ValueError:
print("Conversion failed")
num = 0
else:
# Runs only if NO exception
print(f"Conversion succeeded: {num}")
finally:
print("Cleanup complete")
# Resource tracking
class Resource:
def __init__(self, name):
self.name = name
print(f" Acquired: {name}")
def close(self):
print(f" Released: {self.name}")
print("\nResource management:")
resource = None
try:
resource = Resource("Database")
# Simulate work
items = [1, 2, 3]
value = items[5] # Error!
except IndexError:
print(" Error during processing")
finally:
if resource:
resource.close()
if __name__ == "__main__":
main()
# Finally block for cleanup
def main():
# Finally always executes
print("Finally block basics:\n")
try:
print("In try block")
result = 10 / 2
print(f"Result: {result}")
except ZeroDivisionError:
print("In except block")
finally:
print("In finally block (always runs)")
# Finally runs even with exception
print("\nWith exception:")
try:
print("In try block")
result = 10 / 0 # raises error
print("This won't print")
except ZeroDivisionError:
print("In except block")
finally:
print("In finally block (runs despite error)")
# Simulated file handling
def process_file(filename):
file_handle = None
try:
print(f"\nOpening {filename}")
file_handle = f"<handle:{filename}>"
if "error" in filename:
raise ValueError("Simulated read error")
print(f"Processing {filename}")
return "SUCCESS"
except ValueError as e:
print(f"Error: {e}")
return "FAILED"
finally:
if file_handle:
print(f"Closing {file_handle}")
result1 = process_file("data.txt")
print(f"Result: {result1}")
result2 = process_file("error.txt")
print(f"Result: {result2}")
# Try-except-else-finally (complete form)
print("\nComplete form:")
value =
try:
num = int(value)
except ValueError:
print("Conversion failed")
num = 0
else:
# Runs only if NO exception
print(f"Conversion succeeded: {num}")
finally:
print("Cleanup complete")
# Resource tracking
class Resource:
def __init__(self, name):
self.name = name
print(f" Acquired: {name}")
def close(self):
print(f" Released: {self.name}")
print("\nResource management:")
resource = None
try:
resource = Resource("Database")
# Simulate work
items = [1, 2, 3]
value = items[5] # Error!
except IndexError:
print(" Error during processing")
finally:
if resource:
resource.close()
if __name__ == "__main__":
main()
finally: runs whether exception occurred or not. Good for cleanup.
Exercise: practical.py
Build a robust input parser with complete exception handling