Python Decorators and a Retry Decorator That Re-Runs a Function Until It Succeeds
Company: Raiffeisenbank
Role: Machine Learning Engineer
Category: Software Engineering Fundamentals
Difficulty: hard
Interview Round: Technical Screen
Explain what a decorator is in Python. Then write a try/retry decorator that repeatedly executes any function until it completes successfully.
### Clarifying Questions
- Should retries be unlimited, as stated, or capped by a maximum number of attempts or a total time?
- Which exceptions should trigger a retry, and which should propagate immediately?
- Should there be a delay between attempts, and should it grow after each failure?
- Must the decorator work both as `@retry` and as `@retry(...)` with arguments, and with `async` functions?
### Part 1 — What a decorator is
Explain what a decorator is and how the `@` syntax works, and give a short example.
```hint Functions are objects
Write out what `@name` above a `def` is equivalent to, without using the `@`.
```
#### What This Part Should Cover
- The mechanics: a callable that takes a function and returns a replacement, applied when the function is defined
- Closures, `*args` and `**kwargs`, and `functools.wraps`
- Decorators with arguments, stacking order, and common built-in decorators
### Part 2 — A retry decorator
Write a decorator that re-executes the decorated function until it completes without raising, then returns its result. It must work for functions with any signature.
```hint Loop inside the wrapper
The retry loop belongs inside the function that replaces the original. Decide what happens to the exception after each failed attempt.
```
#### What This Part Should Cover
- A correct wrapper that passes arguments through, returns the result and keeps the function's metadata
- A retry policy: which exceptions retry, limits, backoff, and re-raising the last error
- When retrying is unsafe, and how to test the decorator
### What a Strong Answer Covers
- A precise explanation of decorators as higher-order functions applied at definition time
- Correct use of closures, `*args` and `**kwargs`, and `functools.wraps`
- A working retry decorator, usable with and without arguments
- A sound retry policy: exception filtering, attempt or time limits, exponential backoff with jitter, re-raising the final error
- Awareness of when retrying is dangerous, such as non-idempotent operations
### Follow-up Questions
- How would you make the same decorator work for `async def` functions?
- Why should a retry decorator not catch `KeyboardInterrupt`, and what changes between catching `Exception` and `BaseException`?
- How would you unit-test the decorator without actually sleeping?
- When is retrying an operation dangerous?
Overview: Explain what a Python decorator is and how the @ syntax works, then write a try/retry decorator that re-runs any function until it succeeds. It tests closures, functools.wraps, decorators with arguments, exception filtering, backoff and safe retry limits.
Read the full Raiffeisenbank Machine Learning Engineer interview experience this question came from