Closure bug

2 snippets across 2 stacks — Python, React

PYPython

Late Binding in Closures

PY · Common Mistakes
syntax
# BAD: variable captured by reference
# GOOD: use default argument to capture value
example
# WRONG: All lambdas see final value of i
funcs_bad = [lambda: i for i in range(4)]
print([f() for f in funcs_bad])

# CORRECT: Capture current value via default arg
funcs_good = [lambda i=i: i for i in range(4)]
print([f() for f in funcs_good])
output
[3, 3, 3, 3]
[0, 1, 2, 3]

Note Python closures capture variables by reference, not by value. The loop variable's final value is what all closures see. The i=i default-argument trick forces a copy at each iteration.

REReact

Stale Closures

RE · Common Mistakes
syntax
// PROBLEM: handler captures old state value
// FIX: use updater function or ref
example
function BrokenCounter() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const id = setInterval(() => {
      // BUG: count is always 0 (captured from initial render)
      setCount(count + 1);
    }, 1000);
    return () => clearInterval(id);
  }, []); // empty deps = closure captures initial count

  return <p>{count}</p>; // stuck at 1
}

function FixedCounter() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const id = setInterval(() => {
      // FIX: updater function always has the latest value
      setCount(prev => prev + 1);
    }, 1000);
    return () => clearInterval(id);
  }, []);

  return <p>{count}</p>; // increments correctly
}

Note Stale closures happen when a callback captures a state value that never updates. Common in setInterval, setTimeout, and event listeners set up in useEffect. Use the updater form of setState or store values in a ref.