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

Shallow Copy of a Nested List

easydebugging

Problem

A flood-fill routine allocates a visited grid, and a configuration loader copies a defaults dictionary before customising it per environment:

import copy

def new_grid(rows: int, cols: int) -> list[list[int]]:
    return [[0] * cols] * rows


def count_region(grid: list[list[int]], r: int, c: int) -> int:
    rows, cols = len(grid), len(grid[0])
    visited = new_grid(rows, cols)
    stack, size = [(r, c)], 0
    while stack:
        i, j = stack.pop()
        if not (0 <= i < rows and 0 <= j < cols) or visited[i][j] or grid[i][j] != grid[r][c]:
            continue
        visited[i][j] = 1
        size += 1
        stack += [(i + 1, j), (i - 1, j), (i, j + 1), (i, j - 1)]
    return size


DEFAULTS = {"timeout": 30, "hosts": ["a.internal"], "retry": {"max": 3}}

def config_for(env: str) -> dict:
    cfg = DEFAULTS.copy()
    if env == "prod":
        cfg["hosts"].append("b.internal")
        cfg["retry"]["max"] = 5
    return cfg

Symptoms: count_region returns sizes that are far too small on a 3×3 grid of identical cells (it reports 3, not 9). Separately, after config_for("prod") has been called once, config_for("dev") returns a config with two hosts and retry.max == 5. Explain both with the same root cause and fix both.

Examples

  • g = new_grid(2, 3); g[0][0] = 1 → expected [[1, 0, 0], [0, 0, 0]]. Actual [[1, 0, 0], [1, 0, 0]]. g[0] is g[1] is True.
  • count_region([[7]*3]*3 ... ) starting at (0, 0) on a grid of nine equal cells → expected 9. Actual 3: marking visited[0][0] also marks visited[1][0] and visited[2][0], so each column is counted once.
  • config_for("dev") after config_for("prod") → expected {"timeout": 30, "hosts": ["a.internal"], "retry": {"max": 3}}. Actual has hosts == ["a.internal", "b.internal"] and retry == {"max": 5}, and DEFAULTS itself has been modified.

Hints

  1. [x] * 3 produces a list with three references. References to what, exactly? Does it call anything on x?
  2. Check g[0] is g[1] for the grid, and cfg["hosts"] is DEFAULTS["hosts"] for the config.
  3. Copying a container copies its top level only. When you need the nested structure copied too, the tool has a different name.

Last reviewed 8 September 2026