When we use a variable name, Python needs to figure out what it refers to. It searches through four scopes in a specific order: L → E → G → B. The first match wins.
print, len, range, int, str...
x = "global"
y = "enclosing"
z = "local"
Local Scope
Variables created inside a function are local. They exist only while the function runs and can’t be accessed from outside.
def greet():
message = "hello" # local to greet()
print(message)
greet() # hello
print(message) # NameError: name 'message' is not defined
Enclosing Scope
When we have nested functions, the inner function can access variables from the outer (enclosing) function.
def outer():
name = "Manish" # enclosing scope for inner()
def inner():
print(name) # found in enclosing scope
inner()
outer() # Manish
Global Scope
Variables defined at the module level (outside any function). Accessible everywhere in the file.
counter = 0 # global
def increment():
global counter # tell Python we mean the global one
counter += 1
increment()
print(counter) # 1
Without the global keyword, Python would treat counter as a new local variable and throw an UnboundLocalError when we try to += it.
Built-in Scope
This is where Python’s built-in functions live — print, len, range, int, str, etc. We can technically override them (please don’t).
# Don't do this — but it shows how scope works
print = "oops" # shadows the built-in print
print("hello") # TypeError: 'str' object is not callable
The global Keyword
Lets us modify a global variable from inside a function. Without it, assigning to a variable inside a function creates a new local one.
x = 10
def change():
global x
x = 20
change()
print(x) # 20
The nonlocal Keyword
Same idea, but for enclosing scope. Lets an inner function modify a variable from the outer function.
def counter():
count = 0
def increment():
nonlocal count # modify the enclosing variable
count += 1
return count
return increment
c = counter()
print(c()) # 1
print(c()) # 2
In simple language, when Python sees a variable name, it checks four places in order: the current function, any enclosing functions, the module level, and finally the built-ins. First match wins. Use global and nonlocal when we need to write to an outer scope — but use them sparingly.