Python Basics – Part 10: Error Handling and Exception Patterns

Error Handling and Exception Patterns in Python

In this part of the Python Basics series, we’ll explore error handling in Python — how to prevent your code from crashing, respond gracefully to unexpected situations, and keep your programs running smoothly.
We’ll look at try, except, else, and finally, discuss common error types, input validation, and best practices for writing robust code.

Understanding Exceptions

In Python, errors that occur during program execution are called exceptions.
For example:

print(int('22'))      # Works fine
print(int('twenty'))  # ValueError: invalid literal for int()

To prevent the program from crashing, you can wrap risky code inside a try block and handle errors using except:

try:
    print(int('twenty'))
except ValueError:
    print("The input was not an integer written in digits.")

print("Continuing program execution...")

Catching Specific Exceptions

It’s always better to handle only the errors you expect — not everything.
Avoid using a bare except: since it catches too much, including system interrupts.

try:
    user_input = '0'
    number = int(user_input)
    print('Result of division:', 100 / number)
except ValueError:
    print("Please enter a valid integer.")
except ZeroDivisionError:
    print("Division by zero is not allowed.")

You can also handle multiple exception types together:

try:
    risky_operation()
except (ValueError, ZeroDivisionError) as e:
    print("Invalid input:", e)

Else and Finally Blocks

The else block runs only if no exception occurs,
and the finally block runs no matter what happens — ideal for cleanup tasks.

try:
    from random import randint
    user_input = ['0', '42'][randint(0, 1)]
    number = int(user_input)
    print("Result:", 100 / number)
except ZeroDivisionError:
    print("Division by zero is not allowed.")
else:
    print("Everything worked fine.")
finally:
    print("Closing files or database connections...")

print("Program continues.")

This structure ensures that even if something fails, necessary cleanup still happens.

Exception Hierarchy and BaseException

Every exception in Python inherits from BaseException.
However, you should almost never catch BaseException, because it also includes system-level exceptions like KeyboardInterrupt and SystemExit.

Example (for learning purposes only):

try:
    e1 = int('two')    # ValueError
except BaseException as e:
    print("Caught:", e)
    print(type(e))

Best practice: Catch Exception or specific errors only.

try:
    ...
except Exception as e:
    print("Something went wrong:", e)

Validating User Input

You can use both try/except or conditional checks (if/elif) for input validation.
The Pythonic approach is usually EAFP“Easier to Ask for Forgiveness than Permission.”

Using try/except

while True:
    try:
        user_input = input("Please enter an integer greater than 0: ")
        number = int(user_input)
        result = 100 / number
    except ValueError:
        print("Please enter digits only.")
    except ZeroDivisionError:
        print("Please do not enter 0.")
    else:
        break

print("Program continues with 100 / input =", result)

Using if/elif

while True:
    user_input = input("Please enter an integer greater than 0: ").strip()
    if not user_input.lstrip('-').isdigit():
        print("Digits only (optionally with a leading minus).")
        continue
    if user_input.startswith('0'):
        print("Please do not start with 0.")
        continue

    number = int(user_input)
    if number <= 0:
        print("Please enter a number greater than 0.")
        continue
    break

Note: str.isdigit() works only for non-negative integers without a sign or decimal point.

Cleanup with finally and Context Managers

Instead of manually closing files in a finally block,
you can use Python’s with statement — a context manager that handles cleanup automatically.

try:
    with open("data.txt") as f:
        data = f.read()
    print("File successfully read.")
except FileNotFoundError:
    print("The file was not found.")

This is cleaner and less error-prone than manual open/close management.

Custom Exceptions and Raising Errors

You can define your own exception classes for specific application errors.

class InvalidUserInputError(Exception):
    """Custom exception for invalid input."""
    pass

Then use it in your program:

user_input = -5
if user_input <= 0:
    raise InvalidUserInputError("Input must be greater than zero.")

You can also re-raise exceptions when handling them:

try:
    do_something()
except ValueError as e:
    log_error(e)
    raise  # re-throw the same exception

Summary

In this part, you learned:

  • How to handle errors gracefully using try, except, else, and finally.
  • Why specific exception handling is safer than generic ones.
  • How to validate user input effectively.
  • The use of with blocks for automatic resource cleanup.
  • How to define and raise custom exceptions.

Leave a Reply

Your email address will not be published. Required fields are marked *