Questions
2 of 18
1Why is using a mutable default argument (e.g., `def f(x=[])`) considered a common pitfall?
2What is the purpose of the `nonlocal` keyword, and how does it differ from `global`?
3How does Python's `for` loop differ conceptually from a C-style `for` loop?
4How does structural pattern matching (`match`/`case`, introduced in Python 3.10) differ from a chain of `if`/`elif` statements?
5What are first-class functions, and how does Python's treatment of functions as objects enable higher-order functions?
6What is the purpose of the `else` clause on `for` and `while` loops, and when does it execute?
7How would you implement memoization for a recursive function, and what tradeoffs exist between manual caching and `functools.lru_cache`?
8What is the difference between positional, keyword, default, `*args`, and `**kwargs` parameters?
9Explain Python's LEGB rule for variable scope resolution.
10How does Python's `for` loop differ conceptually from a C-style `for` loop?
11What are first-class functions, and how does Python's treatment of functions as objects enable higher-order functions?
12How would you implement memoization for a recursive function, and what tradeoffs exist between manual caching and `functools.lru_cache`?
13What is the purpose of the `nonlocal` keyword, and how does it differ from `global`?
14What is the difference between positional, keyword, default, `*args`, and `**kwargs` parameters?
15Why is using a mutable default argument (e.g., `def f(x=[])`) considered a common pitfall?
16How does structural pattern matching (`match`/`case`, introduced in Python 3.10) differ from a chain of `if`/`elif` statements?
17What is the purpose of the `else` clause on `for` and `while` loops, and when does it execute?
18Explain Python's LEGB rule for variable scope resolution.
02 / 18

What is the purpose of the `nonlocal` keyword, and how does it differ from `global`?

Difficulty: 5/10
Functions & Scope, Closures, global and nonlocal Keywords

nonlocal vs global: rebinding names in outer scopes

Both keywords let a function rebind a name that lives in an outer scope instead of creating a new local. global targets the module-level namespace. nonlocal targets the nearest enclosing function scope that already has that name, and it is a SyntaxError if there is none; it can never reach module level. nonlocal exists to make closures with mutable state possible: without it, assignment inside the inner function creates a new local variable.

javascript

The crucial distinction interviewers look for is rebinding versus mutating. You only need these keywords when you assign to the name (x = ..., x += 1). Calling items.append(x) or d[k] = v mutates the object the name points to and works with plain lookup through LEGB. Mechanically, a variable referenced by a nested function is stored in a cell object shared between the outer and inner frames (visible via closure and LOAD_DEREF), and nonlocal makes assignments write into that cell.

Trade-offs and alternatives: nonlocal closures are compact for small callbacks and counters, but state hidden in a closure is hard to inspect, test and reset. For anything non-trivial I prefer a small class with attributes, itertools.count for sequences, or a generator that yields successive values. global should be rare: it creates hidden coupling and complicates tests and concurrency, so prefer passing arguments or using a config object. Closures also keep every referenced outer variable alive, which can retain large objects.

Common mistakes: using global when the variable is in an enclosing function (it will refer to the module-level one, or create a new global), expecting a nonlocal counter shared across threads to be safe (the read-modify-write is not atomic; use a lock or atomic structure, which also matters with free-threaded builds), and forgetting the late-binding behavior of closures defined in loops. nonlocal has existed since Python 3.0 (PEP 3104); Python 2 had no equivalent, so old code used a one-element list workaround.

Scenario Questions

0-2 years experience

  1. 1Write a make_counter() closure that returns a function incrementing and returning a count. What error do you get if you leave out nonlocal?
  2. 2Do you need nonlocal to append to a list defined in the enclosing function? Why or why not?

2-5 years experience

  1. 1What SyntaxError do you get when you use nonlocal on a variable that exists only at module level, and how do the target scopes of nonlocal and global differ?
  2. 2Rewrite the counter closure as a class and with itertools.count. When would you prefer each over nonlocal?

5-8 years experience

  1. 1With three nested functions where the same name appears in two outer levels, which binding does nonlocal use?
  2. 2Callbacks in GUI or async code modify shared state through closures. What pitfalls arise, and when would you switch to an object?

8+ years experience

  1. 1Explain closure cells (__closure__, cell_contents, LOAD_DEREF) and what the compiler emits differently with nonlocal. What are the memory implications of closures that capture large objects?
  2. 2Is a nonlocal counter updated from multiple threads safe? How would you make it safe, and does your answer change under the free-threaded build?

Follow-up Questions

  • Why is no keyword needed to call .append() on a list defined in an enclosing function?
  • What is a closure cell and how can you inspect it?
Share

Share via WhatsApp, X, Facebook, LinkedIn or copy link. Open Graph preview enabled.