1.2.31 · D5Introduction to Programming (Python)

Question bank — global and nonlocal keywords

1,831 words8 min readBack to topic

This is a conceptual drill for the parent topic. No heavy computation here — every item targets a misconception or a boundary case that the assignment rule loves to spring on you. Read the question, cover the right side, commit to an answer out loud, then reveal.

Before the traps, three quick pictures so we share the same vocabulary.

The next figure shows that compile-time decision happening: the compiler scans the whole body first, spots the assignment, and stamps the name "local" before any line runs.


True or false — justify

Reading a global variable inside a function always requires the global keyword.
False. Reading climbs the LEGB ladder automatically; you only need global when you rebind (assign to) the name.
global x and nonlocal x are interchangeable ways of "reaching outward."
False. global jumps to the module (top) level; nonlocal binds to the nearest enclosing function. If the variable lives in an enclosing function, global will not find it there.
If a function only calls mylist.append(5) on a global list, it needs global mylist.
False. .append mutates the object the name already points to — it does not rebind the name (label stays put). See Mutable vs Immutable objects; no global needed.
Putting global count at the top of a function creates a brand-new global variable that didn't exist before.
False as stated. global count on its own creates nothing — it only redirects the name. A global count is created only if the function then assigns count and no module-level count existed. Criterion: creation needs both the global declaration and an actual assignment.
nonlocal x can be used inside a top-level (non-nested) function to reach the module variable.
False. nonlocal requires an enclosing function with a binding for x. At the top level there is none, so it raises a SyntaxError.
The UnboundLocalError in the classic count = count + 1 example happens because count doesn't exist.
False. count exists globally, but the assignment made count local, so the local one has no value yet on the right-hand side. See UnboundLocalError.
A function marked global count is no longer a pure function.
True. Rebinding a global means the function has a side effect on shared state — output now depends on and alters the outside world.
You can declare a name both global and nonlocal in the same function.
False. They are mutually exclusive intents for one name; Python raises a SyntaxError because a name can bind to only one outer scope.
In Python 3, a list comprehension has its own scope, so a global/nonlocal name assigned outside it is unaffected by the comprehension's loop variable.
True. The comprehension's loop variable (e.g. i in [i for i in ...]) lives in a hidden nested scope — it does not leak out and cannot clobber an outer i you declared global or nonlocal.

Spot the error

def f():
    print(y)
    y = 10
f()
What breaks and why?
UnboundLocalError. Because y is assigned somewhere in f, it is local for the whole body — so print(y) reads a local that has no value yet.
def outer():
    def inner():
        nonlocal z
        z = 5
    inner()
outer()
Why does this fail?
SyntaxError. nonlocal z needs z to already exist in an enclosing function scope; outer never defines z, so there is nothing to bind to.
total = 0
def add(n):
    total = total + n
add(3)
Fix it and say why the fix works.
Add global total as the first line. Assigning total made it local, so the right-hand total was unbound; global points both sides at the module variable.
def make_counter():
    n = 0
    def step():
        n = n + 1
        return n
    return step
What's the bug in step?
n = n + 1 makes n local to step, shadowing the enclosing n, so it reads an unbound local → UnboundLocalError. Add nonlocal n. See Closures.
x = 1
def g():
    global x
    nonlocal x
    x = 2
Why won't this compile?
SyntaxError — a single name cannot be declared both global and nonlocal; the two intents conflict.
i = 99
def h():
    global i
    squares = [i for i in range(3)]
    return i
After h(), what is the module-level i?
Still the value h left it at via global i, unchanged by the comprehension: in Python 3 the comprehension's i lives in its own hidden scope, so it never touches the global i (which stays 99 since nothing else assigns it).

Why questions

Why does Python decide locality at compile time instead of while running?
So it can compile fast, predictable bytecode: each name-access instruction is chosen once based on whether the name is assigned anywhere in the function, not re-decided every line.
Why does mutating a list not need global but reassigning it does?
list.append changes the object the name points to (no rebinding — label stays). mylist = [...] rebinds the name, which would create a local unless global says otherwise.
Why does global only reach the module level and never an enclosing function?
global was designed as "skip straight to the G in LEGB." Enclosing-function scope is the E level — a different rung — which is exactly why nonlocal exists.
Why does the closure's n survive between calls to the returned function?
The returned inner function keeps a reference to its enclosing scope (a closure), so n is not destroyed when make_counter returns — it lives on (see figure s05). Refer to Closures.
Why is over-using global considered bad style?
It creates hidden side effects and shared mutable state, making functions hard to test, reason about, and reuse — any caller can be affected invisibly.
Why does print(count) work without global but count += 1 doesn't?
print(count) is pure reading (climbs LEGB). count += 1 expands to count = count + 1, which is an assignment (a rebinding) → triggers the "make it local" rule.
Why doesn't a list comprehension's loop variable leak into the surrounding function in Python 3?
Because a comprehension gets its own nested scope (unlike Python 2), so its loop name is local to that mini-scope and never rebinds an outer name — which is why global/nonlocal declared outside stay safe.

Edge cases

If a global variable is only ever read in every function, do you ever need global?
No. Pure reading always climbs outward; global is only for rebinding the name.
What happens if you global x a name that does not exist at module level, then assign it?
The assignment creates x at module level — after the call, x exists globally.
A nested function reads (never assigns) an enclosing variable. Does it need nonlocal?
No. Reading finds it via the E level of LEGB automatically; nonlocal is only for rebinding.
Two nested functions at the same level both nonlocal n. Which n do they bind?
The same n in their common enclosing function — both rebind the one shared variable, so they can communicate through it.
nonlocal with two enclosing functions holding x — which one wins?
The nearest enclosing function's x. nonlocal binds to the closest enclosing scope that has that name.
Can global be used inside a nested function to reach the module variable, skipping the enclosing one?
Yes. global x always targets the module top level, jumping past any enclosing-function x entirely.
If you declare global x but never assign x in the function, does anything change?
Behaviourally nothing observable — reads already reach the global. It is a redundant declaration, though not an error.
Does a comprehension inside a function need nonlocal to read an enclosing variable in its expression?
No. The comprehension can read outer names via LEGB just like any nested scope; it only gets its own scope for the loop variable, not for names it merely reads.

Connections

  • Scope and LEGB rule
  • Functions in Python
  • Closures
  • Mutable vs Immutable objects
  • UnboundLocalError
  • Pure functions and side effects