Python Try...Except

Master error handling and build robust Python applications

๐Ÿ›ก๏ธ Understanding Error Handling

Learn how to handle errors gracefully in Python using try , except , else , and finally blocks. Error handling is crucial for building robust and reliable applications that can gracefully handle unexpected situations.


# Basic try-except example
try:
    result = 10 / 0  # This will raise a ZeroDivisionError
except ZeroDivisionError:
    print("Cannot divide by zero!")
except Exception as e:
    print(f"An error occurred: {e}")
finally:
    print("This code always runs")
                                    
Robust
Applications
Graceful
Handling
Reliable
Code

What is Error Handling?

In programming, errors (also known as exceptions) are events that disrupt the normal flow of a program. Python provides a powerful mechanism to handle these errors, preventing your program from crashing and allowing you to respond to unexpected situations.

The primary constructs for error handling in Python are the try and except blocks.

The try and except Blocks

The try block lets you test a block of code for errors. The except block lets you handle the error.

Basic Syntax

try:
    # Code that might raise an error
    risky_code()
except ExceptionType:
    # Code to execute if ExceptionType occurs
    handle_error()
Basic Try-Except Example
try:
    # Code that might raise an error
    result = 10 / 0
except ZeroDivisionError:
    # Code to execute if ZeroDivisionError occurs
    print("Error: Cannot divide by zero!")
print("Program continues after error handling.")

# Output:
# Error: Cannot divide by zero!
# Program continues after error handling.

Handling Multiple Exceptions

You can handle different types of exceptions by specifying multiple except blocks.

Multiple Except Blocks
try:
    num = int(input("Enter a number: "))
    result = 10 / num
    print(f"Result: {result}")
except ValueError:
    print("Error: Invalid input. Please enter an integer.")
except ZeroDivisionError:
    print("Error: Cannot divide by zero.")
except Exception as e: # Catch-all for any other exceptions
    print(f"An unexpected error occurred: {e}")

# Possible Outputs:
# Enter a number: abc
# Error: Invalid input. Please enter an integer.
#
# Enter a number: 0
# Error: Cannot divide by zero.
#
# Enter a number: 5
# Result: 2.0
Generic Except Block
try:
    my_list = [1, 2, 3]
    print(my_list[5]) # This will cause an IndexError
except Exception as e:
    print(f"An error occurred: {e}")

# Output:
# An error occurred: list index out of range

The else Block

The else block in a try...except statement is executed if no errors occur in the try block.

Try-Except-Else Example
try:
    num1 = int(input("Enter first number: "))
    num2 = int(input("Enter second number: "))
    division_result = num1 / num2
except ValueError:
    print("Invalid input. Please enter valid numbers.")
except ZeroDivisionError:
    print("Cannot divide by zero.")
else:
    print(f"Division successful! Result: {division_result}")
    print("No exceptions occurred.")

# Possible Outputs:
# Enter first number: 10
# Enter second number: 2
# Division successful! Result: 5.0
# No exceptions occurred.
#
# Enter first number: 10
# Enter second number: 0
# Cannot divide by zero.

The finally Block

The finally block, if specified, will be executed regardless if the try block raises an error or not. It's typically used for cleanup operations (e.g., closing files, releasing resources).

Try-Except-Finally Example
file = None
try:
    file = open("non_existent_file.txt", "r")
    content = file.read()
    print(content)
except FileNotFoundError:
    print("Error: The file was not found.")
finally:
    if file:
        file.close()
        print("File closed (if it was opened).")
    print("Cleanup completed.")

# Output:
# Error: The file was not found.
# Cleanup completed.

Raising Exceptions

You can also raise your own exceptions using the raise keyword. This is useful when you want to enforce certain conditions or signal an error in your custom functions.

Raising Custom Exceptions
def validate_age(age):
    if not isinstance(age, int):
        raise TypeError("Age must be an integer.")
    if age < 0:
        raise ValueError("Age cannot be negative.")
    if age < 18:
        raise Exception("User must be at least 18 years old.")
    print(f"Age {age} is valid.")

try:
    validate_age(25)
    validate_age(-5)
except (TypeError, ValueError) as e:
    print(f"Validation Error: {e}")
except Exception as e:
    print(f"General Error: {e}")

# Output:
# Age 25 is valid.
# Validation Error: Age cannot be negative.

Real-World Application: User Input Validation

Error handling is essential for validating user input to ensure your program receives data in the expected format.

Robust Age Input Validation
def get_valid_age():
    while True:
        try:
            age_str = input("Please enter your age: ")
            age = int(age_str)
            if age < 0 or age > 120:
                raise ValueError("Age must be between 0 and 120.")
            return age
        except ValueError as e:
            print(f"Invalid input: {e}. Please try again.")
        except Exception as e:
            print(f"An unexpected error occurred: {e}. Please try again.")

user_age = get_valid_age()
print(f"You entered a valid age: {user_age}")

# Possible Interaction:
# Please enter your age: abc
# Invalid input: invalid literal for int() with base 10: 'abc'. Please try again.
# Please enter your age: -10
# Invalid input: Age must be between 0 and 120.. Please try again.
# Please enter your age: 30
# You entered a valid age: 30

๐Ÿ‹๏ธ Practice Exercise: Safe Division Calculator

Create a Python program that asks the user for two numbers and performs division. Implement error handling to catch ValueError if the input is not a valid number and ZeroDivisionError if the second number is zero. Print appropriate messages for each error and the result if successful.

Solution: Safe Division Calculator
def safe_division_calculator():
    try:
        num1_str = input("Enter the first number: ")
        num2_str = input("Enter the second number: ")

        num1 = float(num1_str)
        num2 = float(num2_str)

        result = num1 / num2
        print(f"The result of {num1} / {num2} is: {result}")

    except ValueError:
        print("Error: Invalid input. Please ensure both inputs are numbers.")
    except ZeroDivisionError:
        print("Error: Cannot divide by zero. The second number cannot be zero.")
    except Exception as e:
        print(f"An unexpected error occurred: {e}")

# Enhanced version with retry logic
def enhanced_calculator():
    while True:
        try:
            num1 = float(input("Enter the first number: "))
            num2 = float(input("Enter the second number: "))
            
            if num2 == 0:
                raise ZeroDivisionError("Division by zero is not allowed")
            
            result = num1 / num2
            print(f"Result: {num1} รท {num2} = {result:.2f}")
            break
            
        except ValueError:
            print("โŒ Please enter valid numbers only!")
        except ZeroDivisionError as e:
            print(f"โŒ {e}")
        except KeyboardInterrupt:
            print("\n๐Ÿ‘‹ Calculator closed by user.")
            break
        except Exception as e:
            print(f"โŒ Unexpected error: {e}")
        
        retry = input("Try again? (y/n): ").lower()
        if retry != 'y':
            break

# Run the calculator
safe_division_calculator()

๐Ÿง  Test Your Knowledge

What is the purpose of the finally block in Python's error handling?

Which keyword is used to explicitly raise an exception in Python?