Exceptions
1. Need for Exceptions
Explanation:
Exceptions are a way for Python to handle errors gracefully without crashing the program. They allow developers to "catch" errors and take corrective actions, ensuring the program's robustness and user-friendly behavior.
For example, when a program tries to divide a number by zero, an exception is raised to indicate an error. Without exception handling, the program would terminate unexpectedly.
2. Syntax Errors vs Runtime Errors
Explanation:
-
Syntax Errors: These occur when the Python interpreter cannot understand the code because it violates the rules of the Python language. These errors are detected before the program runs.
-
Runtime Errors: These occur while the program is running, often due to invalid operations like dividing by zero or accessing an undefined variable.
Example:
# Syntax Error Example
if True
print("Missing colon") # This will raise a syntax error
# Runtime Error Example
num = 10 / 0 # This will raise a ZeroDivisionError
3. What is an Exception
Explanation:
An exception is an event that disrupts the normal flow of a program. When an error occurs, Python creates an exception object, which is then handled by the program or terminates the program if not handled.
4. Workflow of an Exception (Normal Flow vs Error Flow)
Normal Flow:
- Code executes sequentially.
- No interruptions or errors.
Error Flow:
- Code encounters an error (exception).
- Python raises an exception.
- If handled, the program continues to run; otherwise, it terminates.
Diagram (Conceptual):
Start
|
Try Block
|
+---------------------------+
| |
No Exception Exception Occurred
| |
Else Block Except Block
| |
Finally Block (Always Runs) |
| |
+-------------------+
|
End
5. Syntax of an Exception
Explanation:
Python provides a try-except
block to handle exceptions. Optionally, you can add else
and finally
clauses.
Syntax:
try:
# Code that might raise an exception
except ExceptionType as e:
# Code to handle the exception
else:
# Code to execute if no exception occurs
finally:
# Code to execute regardless of whether an exception occurs
6. Understanding Exception Handling Blocks
6.1 The try
Block
The try
block contains the code that might raise an exception. Python executes this block first. If no exception occurs, the program skips the except
block and moves to the else
block (if present).
6.2 The except
Block
The except
block is where you define how to handle specific exceptions. You can catch multiple exception types or use a generic except
to catch all exceptions.
Example:
try:
num = int(input("Enter a number: "))
result = 10 / num
except ZeroDivisionError:
print("Cannot divide by zero.")
except ValueError:
print("Invalid input. Please enter a number.")
6.3 The else
Block
The else
block runs if no exceptions occur in the try
block. It is often used for code that should only execute when everything goes as expected.
Example:
try:
num = int(input("Enter a number: "))
result = 10 / num
except ZeroDivisionError:
print("Cannot divide by zero.")
else:
print(f"Result: {result}")
6.4 The finally
Block
The finally
block contains code that executes regardless of whether an exception occurs or not. It is typically used for cleanup tasks, like closing files or releasing resources.
Example:
try:
file = open("example.txt", "r")
content = file.read()
except FileNotFoundError:
print("File not found.")
finally:
file.close()
print("File closed.")
7. Raising an Exception
Explanation:
You can raise exceptions explicitly using the raise
statement. This is useful when you want to enforce constraints or signal an error in your program.
Example:
def check_age(age):
if age < 0:
raise ValueError("Age cannot be negative!")
print("Valid age.")
check_age(-5) # This will raise a ValueError
Sample Code: Handling and Raising Exceptions
# Example of Exception Handling
try:
num = int(input("Enter a number: "))
result = 10 / num
print(f"Result: {result}")
except ZeroDivisionError:
print("Cannot divide by zero. Please try again.")
except ValueError:
print("Invalid input. Please enter a number.")
else:
print("Operation successful!")
finally:
print("End of program.")
# Raising an Exception
try:
check_age(-10)
except ValueError as e:
print(f"Caught an exception: {e}")
# 8. Popular Exception Types in Python
---
## Overview
Python provides a wide range of built-in exceptions to handle various error scenarios. Below are some commonly used exception types, their purposes, and examples to illustrate their usage.
---
## 1. `ZeroDivisionError`
Raised when a number is divided by zero.
### Example:
```python
try:
result = 10 / 0
except ZeroDivisionError as e:
print("Cannot divide by zero:", e)
2. ValueError
Raised when a function receives an argument of the correct type but an inappropriate value.
Example:
try:
num = int("abc") # Invalid conversion
except ValueError as e:
print("ValueError occurred:", e)
3. IndexError
Raised when attempting to access an index that is out of range in a list or other sequence.
Example:
try:
lst = [1, 2, 3]
print(lst[5])
except IndexError as e:
print("IndexError occurred:", e)
4. KeyError
Raised when a dictionary key is not found.
Example:
try:
d = {"a": 1, "b": 2}
print(d["c"])
except KeyError as e:
print("KeyError occurred:", e)
5. FileNotFoundError
Raised when an attempt to open a non-existent file is made.
Example:
try:
with open("non_existent_file.txt", "r") as file:
content = file.read()
except FileNotFoundError as e:
print("FileNotFoundError occurred:", e)
6. TypeError
Raised when an operation is applied to an object of an inappropriate type.
Example:
try:
result = "string" + 5 # Invalid operation
except TypeError as e:
print("TypeError occurred:", e)
7. AttributeError
Raised when an invalid attribute reference is made.
Example:
try:
obj = 5
obj.append(10) # Invalid attribute for int
except AttributeError as e:
print("AttributeError occurred:", e)
8. ImportError
Raised when an import statement fails to find the module or cannot load an attribute from the module.
Example:
try:
import non_existent_module
except ImportError as e:
print("ImportError occurred:", e)
9. NameError
Raised when a variable or function name is not found in the local or global scope.
Example:
try:
print(undefined_variable)
except NameError as e:
print("NameError occurred:", e)
10. OverflowError
Raised when the result of an arithmetic operation is too large to be represented.
Example:
try:
import math
print(math.exp(1000)) # Overflow
except OverflowError as e:
print("OverflowError occurred:", e)
Summary
Understanding these exception types can help in writing robust and error-tolerant Python programs. Each exception provides a clear and actionable way to handle specific error scenarios. You can always refer to the Python Documentation for a comprehensive list of exceptions.
Python Exceptions: Practice Exercises
Exercise 1: Catching Exceptions
Task:
Write a program that asks the user to input two numbers and divides the first by the second. Catch any exception that might occur and print an appropriate error message.
### Starter Code:
try:
num1 = int(input("Enter the first number: "))
num2 = int(input("Enter the second number: "))
# TODO: Perform the division and print the result
except ZeroDivisionError:
# TODO: Handle division by zero
except ValueError:
# TODO: Handle invalid input
Exercise 2: Circumvented except
Block
Task:
The program below raises a ValueError
but is designed to catch a ZeroDivisionError
. Fix the program so the exception is handled correctly.
### Starter Code:
try:
value = int("not_a_number") # This raises a ValueError
except ZeroDivisionError:
print("A division error occurred.")
# TODO: Add the correct exception handling
Exercise 3: Using the raise
Statement
Task:
Write a function check_age
that raises a ValueError
if the input age is less than 18. Call this function with a valid and an invalid age and handle the exception in the calling code.
### Starter Code:
def check_age(age):
# TODO: Raise a ValueError if age is less than 18
try:
check_age(15) # Invalid age
print("Age is valid.")
except ValueError as e:
# TODO: Handle the exception
Exercise 4: Loops and Exceptions
Task:
Write a program that continuously asks the user to input numbers until they enter a valid number. Use exception handling to catch invalid inputs (e.g., strings) and prompt the user again.
### Starter Code:
while True:
try:
# TODO: Prompt user for input and convert to integer
# TODO: Print the valid number and break the loop
except ValueError:
# TODO: Print an error message and continue the loop
Exercise 5: Exception Bugs
Task:
Debug the following code. Identify why the finally
block does not execute and fix the issue.
### Starter Code:
try:
file = open("non_existent_file.txt", "r")
content = file.read()
print(content)
# TODO: Add missing exception handling
# TODO: Ensure the file is closed in a finally block
Exercise 6: Exceptions with Data Structures
Task:
Write a program that tries to access a non-existent key in a dictionary. Catch the exception and add the missing key to the dictionary with a default value.
### Starter Code:
my_dict = {"a": 1, "b": 2}
try:
# TODO: Access a key that may not exist
except KeyError:
# TODO: Handle the exception by adding the key with a default value
print(my_dict)
Exercise 7: Multiple Exception Types
Task:
Write a program that handles multiple types of exceptions (e.g., ValueError
, ZeroDivisionError
). Prompt the user for input and handle errors appropriately.
### Starter Code:
try:
# TODO: Prompt the user for two numbers
# TODO: Perform division and print the result
except ValueError:
# TODO: Handle invalid input
except ZeroDivisionError:
# TODO: Handle division by zero