Skip to content
CodeKruPro

Your language · Python

Exceptions

Raising, catching and cleaning up after errors, and custom exceptions.

Learn: Exceptions in Python9 minute read

An exception is an object that Python raises when something goes wrong, such as a missing key, a bad number or a file that is not there. How you handle exceptions decides how clearly a test fails: a good framework turns "something broke" into a message that says what, where and why. Interviewers ask about the hierarchy, the full try statement, raising and chaining, and custom exceptions.

Step 1: the hierarchy

All exceptions inherit from BaseException. Under it sit SystemExit (raised by sys.exit), KeyboardInterrupt (Ctrl+C) and Exception, the parent of everything you normally catch.

BaseException has two branches: SystemExit and KeyboardInterrupt, which except Exception does not catch, and Exception, whose subclasses include ValueError, TypeError, LookupError, OSError and AssertionError.
except Exception catches the lower row, but not Ctrl+C or sys.exit.

ValueError means the right type with a wrong value, as in int("abc"), and TypeError means the wrong type, as in "1" + 1. LookupError is the parent of KeyError and IndexError. A failing assert (a check written in a test) raises AssertionError, which pytest (the usual Python test tool) reports as a test failure.

Python has no checked exceptions: nothing forces a function to declare or catch anything. Java has checked exceptions, which the compiler forces you to catch or declare. Document what a function raises in its docstring (the text in triple quotes under def) and test it with pytest.raises (a pytest helper that passes only when that exception is raised).

Step 2: try, except, else and finally

  • except blocks (Java calls them catch) are tried top to bottom and the first match wins, so list specific types first. Python does not reject a general block placed first; the later blocks just never run.
  • A tuple catches several types: except (KeyError, IndexError) as e:.
  • else runs only when the try block raised nothing.
  • finally always runs, even after return.
  • A bare except: also catches KeyboardInterrupt and SystemExit. Write except Exception: if you truly must catch broadly.
def parse(text):
    try:
        value = int(text)
    except ValueError:
        print("except", end=" ")
        return None
    else:
        print("else", end=" ")
        return value
    finally:
        print("finally", end=" ")

print(parse("42"))
print(parse("abc"))

def risky():
    try:
        return 1
    finally:
        return 2          # wins, and would hide errors: avoid

print(risky())

data = {"users": []}
try:
    first = data["users"][0]
except (KeyError, IndexError) as e:
    print("lookup failed:", type(e).__name__)
else finally 42
except finally None
2
lookup failed: IndexError

risky() returns 2, because a return in finally replaces the real result and can swallow an exception. Never return from finally.

Step 3: raise, raise from and custom exceptions

raise ValueError("timeout must be positive") raises an exception. Inside an except block, a bare raise raises the current exception again with its original traceback, for example after logging it. raise NewError(...) from e wraps a low-level error in a clearer one and keeps the original as its cause, so the traceback (the list of calls that led to the error) shows both.

For your own exceptions, subclass Exception, end the name with Error, and add fields if callers need details. One base class with specific subclasses lets callers catch the whole family at once.

import json

class FrameworkError(Exception):
    pass

class DataFileError(FrameworkError):
    def __init__(self, message, file=None):
        super().__init__(message)
        self.file = file

def load_users(path):
    try:
        with open(path, encoding="utf-8") as f:
            return json.load(f)
    except FileNotFoundError as e:
        raise DataFileError(f"Cannot read {path}", file=path) from e

try:
    load_users("missing_users.json")
except FrameworkError as e:
    print(type(e).__name__, "-", e, "-", e.file)
    print("cause:", type(e.__cause__).__name__)
DataFileError - Cannot read missing_users.json - missing_users.json
cause: FileNotFoundError

Step 4: with statements

A with block guarantees clean-up, like Java's try-with-resources (a try that closes things for you). The object's __enter__ method runs at the start and __exit__ at the end, even if the block raises. Files, locks and pytest.raises all work this way, and a pytest fixture (a function that prepares things for a test) with yield gives the same guarantee for set-up and teardown (clean-up after the test).

How to answer in an interview

Start with the shape of the tree, then connect it to tests: "Everything comes from BaseException. I catch subclasses of Exception, never a bare except, so Ctrl+C still works. Python has no checked exceptions, so I document what a function raises and test it with pytest.raises." For custom exceptions, show a small class and a raise ... from e line.

Common mistakes

  • try: ... except: pass around a test step, which can turn a real failure into a pass.
  • Putting except Exception before a more specific block.
  • Wrapping an error without from e, which loses the original cause.
  • Returning from finally.
  • Using exceptions for normal checks. To test that an element is absent, check that find_elements returns an empty list.

Recap

BaseException is the root, and Exception is what you catch. There are no checked exceptions. else runs on success and finally always runs. Use raise ... from e to keep causes, subclass Exception for your own errors, and use with for clean-up.

10 questions0/10 solved

StatusQuestionDifficultyAsked in
Not startedWhere do exceptions sit in the hierarchy?EasyAsked in: Accenture, Infosys, TCS +1
Not startedThe Python exception hierarchy (and no checked exceptions)Easy-MediumAsked in: Accenture, Infosys, TCS +1
Pro+raise, raise from, and the Python answer to throwsEasyAsked in: Capgemini, Infosys, TCS +1
Pro+try, except, else and finally: the rulesMediumAsked in: Accenture, Capgemini, Cognizant +2
Pro+except Exception before except ValueErrorMediumAsked in: Accenture, Capgemini, Cognizant +2
Pro+return in try and finallyMediumAsked in: Accenture, Capgemini, Cognizant +2
Pro+Write and use a custom exceptionMediumAsked in: Wipro
Pro+What does a with statement guarantee?MediumAsked in: Infosys, TCS
Pro+Why is a bare except a problem?Easy-MediumAsked in: Accenture, Capgemini, Cognizant +2
Pro+When does the else of a try run?Easy-MediumAsked in: Accenture, Capgemini, Cognizant +2
Not startedNot startedIn progressIn progressSolvedSolvedPro+Pro+

The first 2 questions of each topic are free. Pro+ opens every question.

Back to the plan