Python Global vs Local Variables Explained Visually
A visual beginner guide to Python global vs local variables. Learn how scope works, what the global and nonlocal keywords do, and how to avoid the most common scope bugs.
Python global vs local variables is one of the topics that beginners can read about three times and still feel uncertain about. The reason is that the rules are simple to state but easy to mix up under pressure. A name defined inside a function belongs to that function unless something explicitly says otherwise. A name defined at the top of a module belongs to the module. The trouble starts when a function tries to read a global, write a global, or interact with a name in an enclosing function. This guide draws those layers visually and points at the exact places where bugs creep in.
A Picture of Python Scope
Picture three nested boxes. The innermost box is the function you are currently writing. The middle box is any function that surrounds it, if there is one. The outermost box is the module, which holds the variables you defined at the top of the file. When Python looks up a name, it searches these boxes from the inside out. The first box that contains a matching name wins. If no box contains the name, Python raises a NameError.
Adding a fourth box on the outside that holds Python's built-in names completes the picture. The full lookup order, from inside to outside, is local, enclosing, global, and built-in. This sequence is called LEGB by Python folklore, and the four letters are worth memorising because they tell you exactly where to look when a name is not behaving the way you expect. To revisit how variables are introduced and named in the first place, our walkthrough on Python variables explained for complete beginners pairs nicely with this scope picture.
What Local Variables Really Are
A local variable in Python is any name that is assigned to inside a function body, anywhere in the function, including inside a nested if or for block. The moment Python sees an assignment inside a function during parsing, the name is marked as local for the entire function. This rule is what makes scope feel surprising sometimes, because the local status applies even on the lines before the first assignment, not just on or after it.
counter = 0
def increment():
counter = counter + 1The function above looks like it should bump the global counter, but Python sees an assignment to counter inside the function, marks counter as local for the whole function, and then raises UnboundLocalError on the right hand side because the local counter has not been assigned yet when the right hand side runs. The fix is to either declare the name global at the top of the function or to pass the value in as an argument. The lesson is that the local rule is decided by where the name is written to, not where it is first read. To revisit the related topic of how parameters and return values move data into and out of a function, our piece on Python return statements explained beyond basics sits next to this one cleanly.
When the Global Keyword Earns Its Place
The global keyword tells Python that a particular name inside a function should refer to the module level variable of the same name, both for reads and for writes. Without global, an assignment creates a local variable. With global, an assignment changes the module level variable directly. The right time to use the global keyword is rare, mainly limited to scripts that keep state in a small module level variable for simplicity.
The reason to use the keyword sparingly is that functions that mutate module level state are harder to test, harder to reason about, and harder to refactor later. The straightforward alternative is to pass values in as arguments and to return new values out as results. A function that takes its inputs and returns its outputs has no implicit dependencies, and you can copy it into a different program without rewriting anything. Whenever you find yourself reaching for the global keyword, ask first whether the function could accept the variable as an argument and return the new value, which is almost always a cleaner design.
Nonlocal and the Middle Layer
The nonlocal keyword targets the enclosing function rather than the module. It exists for the case where a function defined inside another function needs to update a variable in the outer function's scope. Closures and decorators are the natural place to use it, although a beginner can go a long time without needing the keyword in everyday scripts. The mechanics mirror the global keyword exactly, with the difference being which box in the picture is being targeted.
def make_counter():
count = 0
def step():
nonlocal count
count += 1
return count
return stepThe example above creates a small counter object using a closure. Without the nonlocal keyword, the inner function would treat count as its own local variable and the same UnboundLocalError would show up. With the keyword, count refers to the variable in the enclosing scope, and the inner function can update it across calls. For a closer look at functions defined inside other functions and how methods relate to them, our walkthrough on Python functions vs methods explained clearly is a natural follow up.
Frequently Asked Questions
What is the difference between a global and a local variable in Python?
What does the Python global keyword actually do?
Why does my Python function raise UnboundLocalError?
Conclusion
Python scope follows a simple rule, but the rule has a few sharp edges. Names assigned inside a function are local for the entire function, even before the first assignment. The lookup order goes from local, to enclosing, to global, to built-in. The global keyword promotes a name to the module level for both reads and writes. The nonlocal keyword does the same for an enclosing function. Picturing the LEGB boxes makes every scope question answerable in seconds. The single most useful exercise is to recreate the increment function above on your own, watch the UnboundLocalError, and then fix it three ways: by passing the value as an argument, by adding the global keyword, and by wrapping the function in another function and using nonlocal. Three small experiments cover ninety percent of the scope situations you will meet in real code.
More in this topic
Python Dictionary Comprehensions Explained with Examples
A practical beginner guide to Python dictionary comprehensions. Learn the syntax, the filter clause, the inversion pattern, and when to reach for a regular loop instead.
Python List Comprehensions Explained Step by Step
A step by step beginner guide to Python list comprehensions. Learn the shape, the filter clause, the nested form, and when to reach for a regular loop instead.
Python *args and **kwargs Explained the Easy Way
A clear beginner guide to Python *args and **kwargs. Learn what the stars do, how to use both in function signatures, and the patterns that make flexible functions readable.