Gyaan

Exception Handling

beginner exceptions try-except error-handling finally

When something goes wrong in Python, it raises an exception. Instead of letting our program crash, we can catch that exception and handle it gracefully. That’s what try/except is for.

The Basics: try/except

We wrap the risky code in a try block and handle the error in except.

try:
    result = 10 / 0
except ZeroDivisionError:
    print("Can't divide by zero!")  # this runs instead of crashing

Catching Specific Exceptions

We should always catch specific exceptions. This way we know exactly what went wrong.

try:
    num = int("hello")
except ValueError:
    print("That's not a valid number!")

We can have multiple except blocks for different error types:

try:
    data = {"name": "Manish"}
    print(data["age"])
except KeyError:
    print("Key doesn't exist")
except TypeError:
    print("Wrong type used")

The else Clause

The else block runs only when no exception occurred. Think of it as the “happy path” code.

try:
    num = int("42")
except ValueError:
    print("Invalid number")
else:
    print(f"Parsed successfully: {num}")  # runs because no error happened

The finally Clause

finally always runs — whether an exception happened or not. It’s perfect for cleanup tasks like closing files or database connections.

try:
    f = open("data.txt")
    content = f.read()
except FileNotFoundError:
    print("File not found!")
finally:
    print("This always runs — cleanup happens here")

Raising Exceptions

We can raise our own exceptions using the raise keyword. This is useful when we want to signal that something is wrong from our own code.

def set_age(age):
    if age < 0:
        raise ValueError("Age can't be negative")
    return age

try:
    set_age(-5)
except ValueError as e:
    print(e)  # "Age can't be negative"

Common Built-in Exceptions

Here are the ones we’ll see most often:

  • ValueError — right type, wrong value (e.g., int("hello"))
  • TypeError — wrong type (e.g., "2" + 2)
  • KeyError — key not found in a dict
  • IndexError — list index out of range
  • FileNotFoundError — file doesn’t exist
  • AttributeError — object doesn’t have that attribute
  • ZeroDivisionError — dividing by zero

The Bare except Anti-pattern

Using except without specifying an exception type catches everything — including things like KeyboardInterrupt and SystemExit. This is almost always a bad idea because it hides bugs.

# Bad — don't do this
try:
    something()
except:
    pass  # silently swallows ALL errors, even Ctrl+C

# Good — catch what we expect
try:
    something()
except (ValueError, TypeError) as e:
    print(f"Handled: {e}")

In simple language, exception handling is our safety net. We wrap risky code in try, catch known problems with except, run cleanup with finally, and celebrate the happy path with else.