Scope is one of those concepts that confuses new Python programmers constantly — not because it is complicated, but because Python hides the rules from you until something breaks. This tutorial explains what scope is, why it exists, and how Python decides which variable you are actually referring to.
Every variable in Python has a scope — the part of your program where that variable can be seen and used. When Python encounters a name like count or message, it has to figure out which variable you mean. Scope is the system that governs that lookup. Understanding it stops a whole class of confusing bugs before they happen.
What Is Scope?
Think of scope as a set of walls around your code. A variable defined inside those walls is only visible inside them. Outside the walls, it does not exist. Python uses this to keep parts of your program from accidentally overwriting each other's data.
Here is the simplest possible example. A variable created inside a function cannot be seen outside it:
def greet():
message = "Hello, Python!" # local to greet()
print(message)
greet() # prints: Hello, Python!
print(message) # NameError: name 'message' is not defined
The variable message only exists while greet() is running. Once the function ends, message is gone. The print(message) outside the function fails because that name does not exist in the outer part of the program.
Python does not require you to declare variables before using them, so scope is entirely determined by where in your code you assign a value to a name.
Now compare that to a variable defined at the top level of your script — outside any function. That variable is visible everywhere in the file:
site_name = "PythonCodeCrack" # global variable
def show_site():
print(site_name) # reads the global variable just fine
show_site() # prints: PythonCodeCrack
print(site_name) # prints: PythonCodeCrack
Functions can read global variables without any special syntax. Problems only arise when a function tries to assign a new value to a global name — which is covered in Section 3.
Build a function that defines a local variable and prints it. Click each token in the correct order:
def, followed by the function name show_score, empty parentheses (), and a colon :. The body then assigns a local variable score = 10 and calls print(score). The return and global tokens are distractors — they are not needed here.
The Four Scope Levels: LEGB
Python does not just have two scope levels — local and global. It has four. When Python needs to resolve a name, it searches through all four in a fixed order. That order is described by the acronym LEGB.
- Where it is
- Inside the current function
- Example
- Any variable you assign inside a
defblock - Visibility
- Only visible within that specific function call
- Where it is
- The surrounding function, when functions are nested inside other functions
- Example
- A variable in the outer function that an inner function reads
- Visibility
- Readable from inner functions; requires
nonlocalto assign
- Where it is
- The top level of the current module (Python file)
- Example
- Variables and functions defined outside any function
- Visibility
- Readable anywhere in the file; requires
globalto assign from inside a function
- Where it is
- Python's built-in namespace, always available
- Example
print,len,range,type, and all other built-in functions- Visibility
- Available everywhere; searched last so your own names take priority
Python searches those levels in order — Local first, then Enclosing, then Global, then Built-in. It stops as soon as it finds the name. Here is a working example that shows L, E, and G all in action at once:
x = "global" # G — global scope
def outer():
x = "enclosing" # E — enclosing scope
def inner():
x = "local" # L — local scope
print(x) # finds L first → prints: local
inner()
print(x) # finds E → prints: enclosing
outer()
print(x) # finds G → prints: global
You almost never need to use the enclosing scope deliberately in beginner code. The important thing to know is that it exists and that Python checks it between local and global. You will encounter it naturally once you start working with decorators and closures.
This function is supposed to print the value of total after adding 5, but it crashes with a NameError. Click the line you think is wrong, then hit check.
global total as the first line inside add_five(). When Python sees total = total + 5 inside the function, it immediately marks total as a local variable for the entire function — including the earlier print(total) on line 3. Since the local total has not been assigned yet at that point, Python raises an UnboundLocalError. The global keyword tells Python to use the module-level total for both the read and the write.
The global and nonlocal Keywords
Reading a variable from an outer scope is free — Python finds it automatically. But assigning to it from inside a function is a different story. By default, any assignment inside a function creates a new local variable. If you want to modify the outer one, you have to say so explicitly.
Using global
The global keyword tells Python that a name inside the function refers to the module-level variable, not a new local one:
count = 0
def increment():
global count # tells Python: use the global count
count += 1 # modifies the global variable
increment()
increment()
print(count) # prints: 2
Without the global count line, count += 1 would crash with an UnboundLocalError because Python would treat count as a local variable that has never been assigned.
Overusing global makes code hard to follow and test. If you find yourself reaching for it often, consider passing the value as a function parameter and returning the updated result instead.
Using nonlocal
The nonlocal keyword works the same way as global, but for the enclosing function's scope rather than the module-level scope. It is only relevant when you have a function nested inside another function:
def make_counter():
count = 0 # enclosing variable
def increment():
nonlocal count # refers to the enclosing count
count += 1
return count
return increment
counter = make_counter()
print(counter()) # 1
print(counter()) # 2
print(counter()) # 3
Each call to counter() modifies the same count variable in the enclosing make_counter function's scope. Without nonlocal, count += 1 would try to create a new local count inside increment and fail.
"The scope of a name defined in a block extends to that block." — Python Language Reference
How to Control Variable Scope in Python
Follow these four steps whenever you need to reason about or fix a scope-related issue in your Python code.
-
Identify where the variable is defined
Look at the assignment statement for the variable. Is it inside a
defblock (local), inside adefthat is itself inside anotherdef(enclosing), at the top level of the file (global), or is it a Python built-in name likelenorprint? -
Apply the LEGB lookup order
Remember that Python always searches Local first, then Enclosing, then Global, then Built-in. The first scope that contains a matching name wins. If no scope contains the name at all, Python raises a
NameError. -
Use global to modify a module-level variable from inside a function
Place
global variable_nameat the start of the function body before any assignment to that name. This instructs Python to skip creating a new local variable and instead use the one at the module level. Only use this when it is genuinely necessary — passing values in as arguments and returning them is usually cleaner. -
Use nonlocal in nested functions to modify the enclosing function's variable
When you have a function defined inside another function and the inner function needs to assign to a variable that belongs to the outer function, add
nonlocal variable_nameinside the inner function. This is common in counter and closure patterns.
Python Learning Summary Points
- Scope is the region of a program where a variable is visible. Variables defined inside a function are local to that function and cannot be seen from outside it.
- Python follows the LEGB rule when looking up a name: Local, Enclosing, Global, Built-in — in that order. Python stops searching as soon as it finds the name.
- Reading a variable from an outer scope works automatically. Assigning to one requires
global(for module-level variables) ornonlocal(for enclosing-function variables) inside the function body.
Scope bugs are nearly always caused by one of two things: expecting a local variable to be visible outside its function, or trying to assign to a global variable without the global keyword. Knowing the LEGB rule lets you predict exactly what Python will do before you run a single line.
Frequently Asked Questions
Scope in Python refers to the region of a program where a variable is accessible. A variable created inside a function is only visible inside that function. A variable created at the top level of a script is visible throughout the entire file.
The LEGB rule describes the order Python searches for a variable name: Local first, then Enclosing (the surrounding function in nested functions), then Global (the module level), then Built-in (Python's built-in names like len and print). Python stops searching as soon as it finds a match.
A local variable exists only inside the function where it is created. A global variable is defined outside any function and is accessible from anywhere in the module. Local scope takes priority over global scope when both use the same name.
The global keyword tells Python that a variable inside a function refers to the global variable with the same name rather than creating a new local one. Without it, assigning a value to a name inside a function always creates a local variable.
The nonlocal keyword is used inside a nested function to tell Python that a variable belongs to the enclosing (outer) function's scope, not the inner function's local scope and not the global scope.
Yes. A function can read a variable from an outer scope without any special keyword. However, if it tries to assign a new value to that name, Python creates a local variable instead. To assign to the outer variable, use the global or nonlocal keyword.
Enclosing scope applies when a function is defined inside another function. The inner function has access to variables in the outer (enclosing) function. This is the 'E' in the LEGB rule and it only applies with nested functions.
Python follows the LEGB rule and uses the local variable first. The global variable with the same name is not affected and retains its original value outside the function.