Learn What Scope Is in Python: Absolute Beginners Tutorial

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:

python
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.

Note

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:

python
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.

code builder click a token to place it

Build a function that defines a local variable and prints it. Click each token in the correct order:

your code will appear here...
score print(score) def return show_score = : ( ) 10 global
Why: A function definition starts with 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 def block
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 nonlocal to 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 global to 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:

python
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
Pro Tip

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.

spot the bug click the line that contains the bug

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.

1 total = 100
2 def add_five():
3 print(total)
4 total = total + 5
5 add_five()
The fix: Add 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:

python
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.

Watch Out

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:

python
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.

  1. Identify where the variable is defined

    Look at the assignment statement for the variable. Is it inside a def block (local), inside a def that is itself inside another def (enclosing), at the top level of the file (global), or is it a Python built-in name like len or print?

  2. 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.

  3. Use global to modify a module-level variable from inside a function

    Place global variable_name at 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.

  4. 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_name inside the inner function. This is common in counter and closure patterns.

Python Learning Summary Points

  1. 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.
  2. 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.
  3. Reading a variable from an outer scope works automatically. Assigning to one requires global (for module-level variables) or nonlocal (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.

check your understanding question 1 of 5

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.