Python - Built-in Exceptions

Hello, aspiring programmers! Today, we're going to dive into the fascinating world of Python's built-in exceptions. Don't worry if you're new to programming; I'll guide you through this topic step by step, just like I've done for countless students over my years of teaching. Let's embark on this exciting journey together!

Python - Built-in Exceptions

Standard Built-in Exceptions in Python

Imagine you're cooking in the kitchen, and suddenly you realize you're out of a crucial ingredient. That's similar to what happens in programming when an exception occurs - something unexpected that disrupts the normal flow of your code. Python has a variety of built-in exceptions to handle different types of errors.

Let's look at some of the most common built-in exceptions:

  1. SyntaxError: This is like forgetting to put a period at the end of a sentence. Python raises this when it encounters incorrect syntax.

    print "Hello, World!"  # SyntaxError: Missing parentheses in call to 'print'

    In this example, we forgot to add parentheses around the string in the print function, which is required in Python 3.

  2. NameError: This occurs when you try to use a variable that hasn't been defined yet.

    print(x)  # NameError: name 'x' is not defined

    Here, we're trying to print a variable 'x' that we haven't created or assigned a value to.

  3. TypeError: This happens when an operation is performed on an inappropriate type.

    "2" + 2  # TypeError: can only concatenate str (not "int") to str

    In this case, we're trying to add a string ("2") to an integer (2), which Python doesn't know how to do.

  4. ValueError: This is raised when a function receives an argument with the right type but an inappropriate value.

    int("hello")  # ValueError: invalid literal for int() with base 10: 'hello'

    The int() function expects a string that represents a number, not a word.

  5. ZeroDivisionError: This occurs when you try to divide by zero.

    10 / 0  # ZeroDivisionError: division by zero

    Just like in mathematics, division by zero is undefined in programming.

Hierarchy of Built-in Exceptions

Python's built-in exceptions are organized in a hierarchy, much like a family tree. At the top of this tree is the BaseException class, from which all other exceptions inherit.

Here's a simplified version of the exception hierarchy:

Exception Hierarchy
BaseException
├── SystemExit
├── KeyboardInterrupt
├── GeneratorExit
└── Exception
├── StopIteration
├── ArithmeticError
│ ├── FloatingPointError
│ ├── OverflowError
│ └── ZeroDivisionError
├── AssertionError
├── AttributeError
├── BufferError
├── EOFError
├── ImportError
│ └── ModuleNotFoundError
├── LookupError
│ ├── IndexError
│ └── KeyError
├── MemoryError
├── NameError
│ └── UnboundLocalError
├── OSError
│ ├── FileExistsError
│ ├── FileNotFoundError
│ ├── PermissionError
│ └── TimeoutError
├── ReferenceError
├── RuntimeError
│ └── NotImplementedError
├── SyntaxError
│ └── IndentationError
│ └── TabError
├── SystemError
├── TypeError
├── ValueError
│ └── UnicodeError
└── Warning

Understanding this hierarchy can help you catch and handle exceptions more effectively in your code.

How to Use Built-in Exceptions

Now that we know what exceptions are, let's learn how to use them in our code. The primary way to handle exceptions is by using a try-except block. It's like having a safety net when you're learning to ride a bike - if you fall (encounter an exception), the net (except block) catches you.

Here's a basic structure:

try:
    # Code that might raise an exception
    result = 10 / 0
except ZeroDivisionError:
    # Code to handle the specific exception
    print("Oops! You can't divide by zero.")

In this example, we're trying to divide by zero, which we know will raise a ZeroDivisionError. The except block catches this specific error and prints a friendly message instead of crashing the program.

You can also catch multiple exceptions:

try:
    # Code that might raise different exceptions
    number = int(input("Enter a number: "))
    result = 10 / number
except ValueError:
    print("That's not a valid number!")
except ZeroDivisionError:
    print("You can't divide by zero!")
except:
    print("Something else went wrong.")

This script handles different scenarios: if the user enters a non-numeric value (ValueError), tries to divide by zero (ZeroDivisionError), or if any other unexpected error occurs.

Explicitly Raising Built-in Exceptions

Sometimes, you might want to raise an exception yourself. It's like being a referee in a game - when you see something that's not right, you blow the whistle and stop the game.

Here's how you can raise an exception:

def check_age(age):
    if age < 0:
        raise ValueError("Age cannot be negative!")
    elif age < 18:
        print("You're a minor.")
    else:
        print("You're an adult.")

try:
    check_age(-5)
except ValueError as e:
    print(e)

In this example, we're creating a function that checks a person's age. If someone tries to enter a negative age, we raise a ValueError with a custom message. The try-except block outside the function catches this exception and prints the error message.

Remember, raising exceptions should be done judiciously. It's a powerful tool, but overusing it can make your code harder to understand and maintain.

In conclusion, understanding and effectively using Python's built-in exceptions is crucial for writing robust and error-resistant code. It's like learning to navigate the seas - knowing about potential storms (exceptions) and how to handle them will make your programming journey much smoother and more enjoyable.

Keep practicing, stay curious, and don't be afraid of encountering exceptions - they're opportunities to learn and improve your code!

Credits: Image by storyset