ProgrammingBackend Developer

Describe the exception handling mechanisms in Python. How does the try/except/finally block work, what is the purpose of raise, and what common pitfalls can occur?

Pass interviews with Hintsage AI assistant

Answer

In Python, exception handling is implemented using the try/except/else/finally constructs and the raise statement.

The try block defines the code to be protected. If an exception occurs within this block, control is passed to the nearest matching except block. If no exception occurs, the else block (if present) is executed. The finally block is always executed — regardless of whether an exception occurred or not (e.g., to release resources).

The raise statement is used to explicitly raise an exception or to re-raise the current one (in an except block without specifying the type).

Example:

try: x = 1 / 0 except ZeroDivisionError as e: print(f"Error: {e}") else: print("No errors") finally: print("Always executes")

Output:

Error: division by zero
Always executes

Nuances:

  • In nested handlers, the order of except blocks is important: from specific types to more general ones (otherwise, specific ones will not be caught).
  • The finally block cannot prevent the re-throwing of an exception (if raise is used inside finally, the most recent error is what matters).

Trick Question

Question: "What happens if both the try block and finally raise different exceptions?"

Answer: The exception from finally "overrides" the exception from try: what comes out is what was raised in finally.

def foo(): try: raise ValueError("from try") finally: raise IndexError("from finally") try: foo() except Exception as e: print(repr(e)) # Output: IndexError('from finally')

Examples of real mistakes caused by a lack of understanding of this topic


Story

In the ETL process, the database connection was unconditionally closed in the finally block, but it was forgotten that an exception could be raised in finally (for example, if the connection was already closed). The result was a "hidden" exception from finally that completely engulfed the exception from the main code, making debugging significantly more difficult.


Story

Used chains of multiple except blocks: from general except Exception above specific ones. As a result, all specific except blocks remained "dead" — low-level exceptions were not caught separately, complicating the handling of specific errors.


Story

In the web service, it was forgotten to propagate the exception further through "raise" in the except block while logging the error, but allowing execution to continue. As a result, real errors were "lost", and the program continued to operate with an incorrect state.