skip to content

What is the difference between `global` and `nonlocal` in Python?

level: juniorimportance: must knowfreq 65%

answer

  1. Which scope does the assignment land in
  2. Declarations, not runtime operations
  3. One targets the module namespace
  4. The other targets the nearest enclosing function
  5. Reading needs no declaration at all

basics

~20 s

global name makes assignments inside a function rebind the module-level name; nonlocal name rebinds the name in the nearest enclosing function. Without either declaration, an assignment simply creates a new local that shadows the outer one.

solid answer

~40 s

Both are compile-time declarations that change where an assignment lands. By default any assignment inside a function binds a **local** name, so an outer variable is shadowed rather than updated. `global count` tells the compiler that every use of `count` in that function refers to the module namespace, so `count += 1` updates the module-level variable -- and it may even create that variable if it does not exist yet. `nonlocal count` instead targets the nearest enclosing *function* scope; it never reaches module level, and it fails at compile time when no enclosing function binds the name. Neither is needed merely to read an outer name, and neither is needed to mutate an object in place: `readings.append(value)` never rebinds `readings`.

code

python · 18 lines
python
count = 0

def outer():
    count = 100

    def bump_global():
        global count
        count += 1

    def bump_enclosing():
        nonlocal count
        count += 1

    bump_global()
    bump_enclosing()
    return count

print(outer(), count)  # 101 1

go deeper

for a junior

Be ready to state the one-line difference: global targets the module namespace, nonlocal the nearest enclosing function. Also recall that reading an outer name needs no declaration at all -- only rebinding does.

for a middle

Explain the mechanics. Both are compile-time declarations that reclassify the name for the whole function body, global can create a module-level name that did not exist, and nonlocal skips module scope entirely rather than falling back to it.

for a senior

Expect to be asked when you would actually use either in production code. Show that you reach for an object or an explicitly passed parameter first, and that a global in review is a question about who owns that state and for how long.

for a principal

Own the policy angle. Module-level mutable state rebound with global becomes an import-order and test-isolation liability across a codebase, so decide where shared state is allowed to live rather than banning a keyword case by case.

### The rule everything else follows from CPython decides what *kind* of name every identifier in a function is while it **compiles** the function, long before the function ever runs. The rule is short: **if a name is assigned anywhere in a function body, that name is local to that function for the whole body.** "Assigned" is broader than `=`; it includes `x += 1`, `for x in ...`, `with ... as x`, `except E as x`, `import x`, `def x` and `class x`. A name that is only *read* is not local, and the compiler resolves it outward instead. That single rule is why an inner assignment **shadows** an outer variable rather than updating it. A function that does `count = count + 1` when `count` is a module-level variable is not incrementing anything outer; it declared its own `count` by assigning to it. `global` and `nonlocal` exist to override that classification. ### `global name` `global name` is a **declaration**, not code that does work at runtime. It tells the compiler that for the entire body of the enclosing function, `name` refers to a binding in the **module namespace** -- specifically the namespace of the module where the function was *defined*. Python's scoping is lexical, not dynamic, so the caller's module is irrelevant. Three consequences are worth memorising: * **It can create the name.** `global registry` followed by `registry = {}` installs a module attribute that did not exist before the call. Nothing has to pre-exist, because a module namespace is an ordinary dictionary that can gain a key at any moment. * **It skips every enclosing function.** A `global count` inside a function nested three deep still means the module-level `count`, even if two of the enclosing functions have their own `count`. * **It applies to the whole body, not just the lines after it.** Writing the declaration halfway down is legal in principle but CPython rejects reading the name before the declaration appears with `SyntaxError: name 'g' is used prior to global declaration`. Put the statement at the top of the function so the intent is visible. ### `nonlocal name` `nonlocal name` targets the nearest **enclosing function** scope that binds that name. It is the tool for closures: an inner function that must *update*, not merely read, a variable belonging to the factory that created it. It differs from `global` in two ways that interviewers probe: * **It never reaches module scope.** If the only `count` in the file is a module-level one, `nonlocal count` is an error, not a fallback. `nonlocal` at module level is rejected outright with `nonlocal declaration not allowed at module level`. * **It requires an existing binding.** The compiler searches enclosing function scopes for a binding of that name, and if there is none the module fails to compile with `SyntaxError: no binding for nonlocal 'count' found`. `global` never fails this way. The asymmetry is deliberate: module namespaces grow at runtime, function scopes are settled at compile time. Declaring the same name both `global` and `nonlocal` in one function is a contradiction and is rejected with `SyntaxError: name 'g' is nonlocal and global`. ### What neither statement is for **Reading.** A function reads outer names with no declaration at all. `print(TIMEOUT)` inside a function finds the module-level `TIMEOUT` with nothing declared, and an inner function reads its factory's variables the same way. Adding `global TIMEOUT` to a function that only reads it is noise. **Mutating an object in place.** `readings.append(value)`, `cache[key] = value` and `config.update(...)` do not rebind anything -- they look the name up, get an object, and call a method on it. No declaration is required or useful. The distinction between *rebinding a name* and *mutating the object a name refers to* is the single most valuable idea in this whole area, and it is what separates a candidate who has understood Python's data model from one who has memorised keywords. The one trap in that story is augmented assignment on a mutable object: `readings += [value]` mutates the list in place *and* stores the result back to the name, so inside a function it counts as an assignment and makes the name local. ### Choosing between them in real code `nonlocal` is the healthier of the two. Its target is a variable owned by a single enclosing call, its lifetime is bounded by that call, and a typo is caught when the file is imported. It powers the accumulator and call-counter idioms and most decorators that keep per-decoration state. `global` is the one to justify in review. It reaches the widest namespace a module has, the state it writes lives as long as the process, and no function signature reveals that the write happened. The defensible uses are narrow: installing a lazily-built resource behind a single accessor function, and little else. Module-level *constants* are fine -- they are read without any declaration and never rebound, so no `global` statement appears at all. When you find yourself typing `global` to avoid passing a parameter, the honest fix is a parameter or an object.

  • Do you need `global` to append to a module-level list from inside a function?
    No. `global` is only about rebinding a name. `readings.append(value)` looks `readings` up in the module namespace and mutates the object it finds, so no declaration is required. You only need `global readings` if you write `readings = []` -- or `readings += [value]`, because augmented assignment stores back to the name and therefore counts as an assignment.
  • Can a `global` declaration inside a nested function reach the enclosing function's variable?
    No. `global` always means the module namespace and it skips every enclosing function scope. A nested function that declares `global count` reads and writes the module-level `count` even when its enclosing function has a local `count` of its own. Reaching the enclosing one requires `nonlocal`.
  • Does the position of a `global` statement inside the function body matter?
    The declaration applies to the whole body, not only the lines below it, but CPython rejects using the name before the declaration appears: `SyntaxError: name 'g' is used prior to global declaration`. By convention the statement goes on the first line of the function so a reader sees the intent immediately.

Assigning inside a function is writing on your own scratch pad. nonlocal is the note that says write on my supervisor's pad instead; global says write on the noticeboard in the lobby, skipping every supervisor in between.

saying these in an interview costs you the question

  • Says `nonlocal` can rebind a module-level variable
  • Thinks `global` is needed just to read a module-level name
  • Believes `global` reaches the enclosing function's local variable
  • Claims `global` is required to call `append` on a module-level list
  • Treats `global` as a runtime operation rather than a compile-time declaration
  • Confuses shadowing an outer name with reassigning it

context