Scopes in Python — LEGB Rule Explained
What is Scope?
Scope determines where a variable is accessible. Python uses the LEGB rule to resolve variable names - it searches in this order:
Local Scope
def my_function():
x = 10 # local variable - only exists inside this function
print(x)
my_function() # 10
# print(x) # NameError: name 'x' is not defined
# Each function call gets its own local scope
def counter():
count = 0
count += 1
return count
print(counter()) # 1
print(counter()) # 1 (fresh scope each call)
Global Scope
message = "Hello" # global variable
def greet():
print(message) # can READ global variable
greet() # Hello
# To MODIFY a global variable inside a function, use 'global'
count = 0
def increment():
global count
count += 1
increment()
increment()
print(count) # 2
# Without 'global', Python creates a new local variable
def bad_increment():
count = count + 1 # UnboundLocalError!
Enclosing Scope & Closures
When a nested function references a variable from its enclosing function, it creates a closure.
def outer(x):
def inner(y):
return x + y # 'x' is from enclosing scope
return inner
add5 = outer(5)
add10 = outer(10)
print(add5(3)) # 8
print(add10(3)) # 13
# Closure remembers the enclosing scope
def make_counter():
count = 0
def increment():
nonlocal count # modify enclosing variable
count += 1
return count
return increment
counter = make_counter()
print(counter()) # 1
print(counter()) # 2
print(counter()) # 3
# Each call to make_counter() creates an independent counter
counter2 = make_counter()
print(counter2()) # 1 (independent)
nonlocal Keyword
def outer():
x = 10
def inner():
nonlocal x # refers to outer's x
x = 20
print(f"inner: x = {x}")
inner()
print(f"outer: x = {x}") # x was modified by inner
outer()
# inner: x = 20
# outer: x = 20
# LEGB in action
x = "global"
def outer():
x = "enclosing"
def inner():
x = "local"
print(x) # local
inner()
print(x) # enclosing
outer()
print(x) # global
Built-in Scope
import builtins
# See all built-in names
print(dir(builtins))
# Built-ins are always available
print(len([1, 2, 3])) # 3
print(type("hello")) # <class 'str'>
print(range(5)) # range(0, 5)
# You can shadow built-ins (but don't!)
# list = [1, 2, 3] # now 'list' is a variable, not the built-in!
# list([1, 2]) # TypeError!
# Check if a name is a built-in
print(hasattr(builtins, "print")) # True
print(hasattr(builtins, "myvar")) # False
Level Up Your Python Skills
Master Python with these hand-picked resources
10,000+ learners
Free forever
Updated 2026
Related Python Topics