← Hudson River Trading Interview Insights

Hudson River Trading·Software Engineer·Technical Phone Screen·Senior

Senior
Jun 2026

Summary

Technical phone screen for a full-stack role at HRT, basically one long deep-dive into Python context managers. They went way further than I expected, from the basics of the protocol all the way to ExitStack and re-entrant contexts.

Questions Asked (6)

Q1

Walk me through how the context manager protocol works in Python, including what __enter__ and __exit__ do, how the `with` statement fits in, and what it means for __exit__ to return True.

Technical Trade-offsAlgorithms & Data Structures
Author's notes

I covered the basics fine but fumbled the return value part.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by defining the context manager protocol as a way to manage resources with guaranteed cleanup, then explain the `with` statement's role in invoking `__enter__` and `__exit__`. Walk through a concrete example like file handling, and clarify that `__exit__` returning True suppresses exceptions, while False or None propagates them.

Pro tip: Mention that context managers are not just for resource cleanup—they can also be used for temporary state changes, and that `contextlib.contextmanager` offers a simpler way to create them. This shows depth and awareness of Pythonic idioms.

1. Define the protocol

Explain that a context manager is any object implementing `__enter__` and `__exit__`, which define setup and teardown logic for a block of code.

2. Describe the `with` statement

Detail how `with` calls `__enter__` on the context manager, binds its return value to an optional variable, executes the block, and always calls `__exit__` even if an exception occurs.

3. Explain `__enter__` and `__exit__`

Clarify that `__enter__` sets up the resource and can return it, while `__exit__` receives exception type, value, and traceback, and is responsible for cleanup.

4. Discuss `__exit__` return value

State that if `__exit__` returns True, any exception is suppressed; otherwise, the exception propagates. Emphasize that returning True should be done only when the context manager can meaningfully handle the exception.

5. Provide an example

Use a file handling example to illustrate: `with open('file.txt') as f:` ensures the file is closed even if an error occurs, and mention that `__exit__` returns None (so exceptions propagate).

Key Points to Mention

  • The `with` statement ensures `__exit__` is called even if an exception is raised inside the block.
  • `__enter__` can return a value that is assigned to the variable after `as`.
  • `__exit__` receives three arguments: exception type, exception value, and traceback; if no exception, all are None.
  • Returning True from `__exit__` suppresses the exception, effectively swallowing it.
  • Returning False or None (or anything else) allows the exception to propagate.
  • Context managers can be implemented as classes or using `contextlib.contextmanager` decorator for generator-based ones.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q2

Implement a context manager as a class using __enter__ and __exit__, then implement the same thing using contextlib.contextmanager with a generator.

Algorithms & Data StructuresTechnical Trade-offs
Author's notes

The class-based version was fine.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clearly explaining the purpose of context managers and the two implementation approaches. Then, write a class-based context manager with __enter__ and __exit__, followed by a generator-based one using @contextmanager. Finally, compare their trade-offs, such as readability, reusability, and error handling.

Pro tip: Emphasize that the generator-based approach is more concise but the class-based approach offers better reusability and explicit state management. Mention that @contextmanager is implemented using the class-based protocol under the hood, showing deeper understanding.

1. Explain context managers

Briefly define what a context manager is and why it's useful (e.g., resource management, exception safety). Mention the with statement and the context management protocol.

2. Implement class-based context manager

Write a class with __enter__ and __exit__ methods. Show how __enter__ returns the resource and __exit__ handles cleanup and exceptions.

3. Implement generator-based context manager

Use the @contextmanager decorator on a generator function. Show the try/finally block with yield to separate setup and teardown.

4. Compare and contrast

Discuss trade-offs: class-based is more explicit and reusable, generator-based is more concise but single-use. Mention exception handling differences.

5. Provide examples and edge cases

Give a concrete example (e.g., file handling or timing) and mention edge cases like exception suppression and reentrancy.

Key Points to Mention

  • The context management protocol: __enter__ and __exit__ methods.
  • __exit__ receives exception type, value, and traceback; returning True suppresses the exception.
  • @contextmanager uses a generator that yields exactly once; code before yield is setup, after is teardown.
  • Generator-based context managers are single-use, while class-based can be reused if designed properly.
  • Exception handling: in generator-based, use try/finally to ensure cleanup; in class-based, handle in __exit__.
  • Real-world examples: file opening, database connections, locks, timing blocks.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q3

Write a timing context manager that measures and prints elapsed time when the block exits.

Algorithms & Data Structures
Author's notes

Easy one.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Implement a context manager class with __enter__ and __exit__ methods that record start and end times using time.perf_counter, then print the elapsed time. Alternatively, use the contextlib.contextmanager decorator with a generator function for a more concise solution. Ensure the timing is accurate and handles exceptions properly.

Pro tip: Mention that time.perf_counter() is preferred over time.time() for measuring short durations due to its higher resolution and monotonicity, and note that the context manager should not suppress exceptions unless explicitly intended.

1. Choose implementation approach

Decide between a class-based context manager or a generator-based one using contextlib. Briefly explain the trade-offs (e.g., class-based is more explicit, generator-based is more concise).

2. Record start time

In __enter__ (or before yield in the generator), capture the start time using time.perf_counter() and return self (or any desired value).

3. Record end time and compute elapsed

In __exit__ (or after yield), capture the end time, compute the difference, and format the elapsed time appropriately (e.g., seconds with milliseconds).

4. Print elapsed time

Print the elapsed time in a clear, readable format, possibly including a label for context.

5. Handle exceptions and cleanup

Ensure that the timing still occurs even if an exception is raised inside the block. In __exit__, return False (or None) to propagate exceptions unless suppression is desired.

Key Points to Mention

  • Use time.perf_counter() for high-resolution, monotonic timing.
  • Implement __enter__ and __exit__ methods for class-based context manager.
  • Alternatively, use @contextlib.contextmanager decorator with a generator.
  • Ensure the context manager does not suppress exceptions by default.
  • Consider formatting the elapsed time for readability (e.g., f'{elapsed:.4f} seconds').
  • Mention that the context manager can be reused if implemented as a class.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q4

Implement a context manager that manages a resource like a file handle, database connection, or lock, and guarantees cleanup even if an exception is raised inside the block.

Technical Trade-offsSystem Design
Author's notes

Went with a database connection example since it felt more interesting than a file.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the resource type and language, then implement a context manager using the language's idiomatic construct (e.g., Python's __enter__/__exit__ or Java's try-with-resources). Emphasize exception safety by ensuring cleanup runs in a finally block or equivalent, and discuss trade-offs like reentrancy, error handling, and performance.

Pro tip: Mention that cleanup should be idempotent and that you should avoid suppressing exceptions unless intentional, as this demonstrates production-level awareness. Also, briefly note how you would test the context manager with exceptions to verify cleanup.

1. Clarify Requirements

Ask about the resource type, language, and whether reentrancy or thread-safety is needed. This shows you consider the context before coding.

2. Design the Interface

Define the context manager's API: what it returns on enter, what it does on exit, and how it handles exceptions. For example, in Python, implement __enter__ and __exit__.

3. Implement Cleanup Logic

Use a try/finally block (or language equivalent) to guarantee cleanup. Ensure the resource is released exactly once, even if an exception occurs.

4. Handle Exceptions and Edge Cases

Decide whether to suppress exceptions, log errors, or propagate them. Consider nested context managers, reentrancy, and resource acquisition failures.

5. Test and Validate

Write tests that simulate exceptions inside the block and verify cleanup. Also test normal exit and resource acquisition failure.

Key Points to Mention

  • Use of try/finally or language-specific constructs (e.g., Python's with statement, Java's try-with-resources) to guarantee cleanup.
  • Exception propagation: whether to suppress, log, or re-raise exceptions, and the implications.
  • Resource acquisition and release: ensuring the resource is properly initialized and released exactly once.
  • Reentrancy and thread-safety: if the context manager can be used concurrently or nested.
  • Idempotent cleanup: making cleanup safe to call multiple times.
  • Testing strategy: how to verify cleanup occurs even when exceptions are raised.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q5

How would you handle nested or re-entrant context managers? What is contextlib.ExitStack and when would you use it?

Technical Trade-offsSystem Design
Author's notes

Honestly the hardest part of the whole interview.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by explaining the mechanics of nested and re-entrant context managers, then introduce contextlib.ExitStack as a solution for dynamic or conditional resource management. Emphasize its role in simplifying complex cleanup logic and ensuring robustness in production systems.

Pro tip: Mention that ExitStack is particularly useful in trading systems where resources like file handles, network connections, and locks must be acquired and released in a strict order, and that it helps avoid resource leaks in error-prone scenarios.

1. Define nested and re-entrant context managers

Explain that nested context managers are used when multiple resources need to be managed, and re-entrant ones allow a single manager to be used multiple times. Highlight that manual nesting can become unwieldy and error-prone.

2. Introduce contextlib.ExitStack

Describe ExitStack as a context manager that simplifies managing multiple context managers dynamically. It allows entering and exiting contexts programmatically and ensures proper cleanup even if exceptions occur.

3. Explain how ExitStack works

Detail that ExitStack maintains a stack of callbacks and context managers, and on exit, it unwinds the stack in reverse order, calling each cleanup. It supports enter_context, callback, and push methods.

4. Discuss use cases and trade-offs

Provide scenarios where ExitStack is beneficial, such as when the number of resources is not known until runtime, or when resources are conditionally acquired. Mention that it adds a slight overhead but greatly improves readability and safety.

5. Relate to system design and trading systems

Connect to the role by explaining how ExitStack can manage resources in high-frequency trading systems, ensuring deterministic cleanup and avoiding leaks that could impact performance or correctness.

Key Points to Mention

  • Nested context managers: using multiple 'with' statements, potential for deep nesting and reduced readability.
  • Re-entrant context managers: a single manager that can be used in multiple 'with' blocks, often implemented with a counter or thread-local state.
  • contextlib.ExitStack: a flexible tool for managing dynamic sets of context managers and cleanup functions.
  • ExitStack methods: enter_context(), callback(), push(), and pop_all().
  • Use cases: conditional resource acquisition, dynamic resource management, and ensuring cleanup in reverse order.
  • Trade-offs: slight performance overhead, but improved code clarity and exception safety.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q6

What are the common pitfalls with context managers, particularly around exception suppression, re-raising, and making cleanup logic safe to call more than once?

Technical Trade-offsAlgorithms & Data Structures
Author's notes

Talked through three things: accidentally returning True from __exit__ and swallowing exceptions you didn't mean to, not handling the case where the cleanup itself raises, and assuming __exit__ only gets called once.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by defining what a context manager is and its purpose, then systematically discuss pitfalls related to exception suppression, re-raising, and idempotent cleanup. Use concrete examples (e.g., file handling, database connections) to illustrate each pitfall and how to avoid them.

Pro tip: Emphasize that cleanup should be idempotent and that suppressing exceptions should be a deliberate, documented decision—never a side effect. Mention that in high-stakes environments like trading, silent failures can be catastrophic, so always log suppressed exceptions.

1. Define context managers and their role

Briefly explain that context managers ensure proper resource acquisition and release, typically using the `with` statement. Highlight that their primary goal is to guarantee cleanup even if exceptions occur.

2. Discuss exception suppression pitfalls

Explain that suppressing exceptions (e.g., by returning True from `__exit__`) can hide critical errors. Stress that suppression should be intentional and limited to specific, well-understood exceptions, with logging.

3. Address re-raising and exception chaining

Describe how to properly re-raise exceptions after cleanup, preserving the original traceback. Mention the use of `raise` without arguments or `raise ... from ...` to maintain context.

4. Ensure idempotent cleanup logic

Explain that cleanup code should be safe to call multiple times, as it might be invoked explicitly or during garbage collection. Use flags or checks to avoid double-free or double-close errors.

5. Summarize best practices and trade-offs

Conclude with best practices: avoid blanket suppression, always log, use contextlib utilities like `suppress` judiciously, and test cleanup paths. Acknowledge trade-offs between robustness and simplicity.

Key Points to Mention

  • Returning True from `__exit__` suppresses exceptions; this should be rare and logged.
  • Use `raise` without arguments to re-raise the current exception, preserving the traceback.
  • Cleanup methods (e.g., `close()`) should be idempotent to handle multiple calls safely.
  • Context managers can be implemented using `contextlib.contextmanager` or classes with `__enter__`/`__exit__`.
  • Exception chaining with `raise ... from ...` helps maintain causality when re-raising.
  • In high-frequency trading, silent failures can lead to financial loss; always log suppressed exceptions.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.