Problem solving · should-tier · asked at Amazon, Apple, Google, Meta, Microsoft, Netflix

Closure Late Binding in a Loop

mediumdebugging

Problem

An HTTP framework registers one handler per route. To avoid repeating the dispatch boilerplate, the handlers are created in a loop:

def dispatch(route: str, request: str) -> str:
    return f"{route} handled {request}"


def build_handlers(routes: list[str]) -> dict[str, "Callable[[str], str]"]:
    handlers = {}
    for route in routes:
        handlers[route] = lambda request: dispatch(route, request)
    return handlers


handlers = build_handlers(["/users", "/orders", "/health"])
print(handlers["/users"]("GET"))

Symptom: every route is handled as if it were /health. The line above prints /health handled GET. The dictionary keys are correct (/users, /orders, /health), only the behaviour is wrong. Explain what is printed and why, and fix build_handlers.

Examples

  • handlers["/users"]("GET") → expected /users handled GET. Actual /health handled GET.
  • handlers["/orders"]("POST") → expected /orders handled POST. Actual /health handled POST.
  • handlers["/health"]("GET") → /health handled GET. Correct only because it happens to be the last route.

Hints

  1. When is the name route inside the lambda looked up: when the lambda is created, or when it is called?
  2. How many distinct variables named route exist in build_handlers? One per iteration, or one for the whole loop?
  3. Give each lambda its own copy of the value at creation time. Default arguments are evaluated at definition time.

Last reviewed 8 September 2026