Python Scope
1. What is Scope?
Scope defines where a variable is accessible in your program.
- Variables defined inside a function are only accessible inside that function (local scope)
- Variables defined outside all functions are accessible everywhere (global scope)
def foo():
x = 0
print(x) # ✅ works — x is in scope here
print(x) # ❌ NameError — x is not accessible outside foo
2. Local vs Global Scope
Global variables are accessible inside functions
x = 1
def foo():
print(x) # ✅ can access global x (no local x defined)
foo() # → 1
Local variables shadow global ones
If a local variable has the same name as a global one, the local one takes priority inside the function.
x = 1
def foo():
x = 0 # this is a NEW local variable, not the global x
print(x) # → 0
foo()
print(x) # → 1 (global x unchanged)
Python first looks for a variable in the local (function) scope. If not found, it looks in the global scope.
3. Block Scope (if / for / while)
Unlike functions, variables defined inside if, for, or while blocks are accessible outside them — as long as they were created.
inp = int(input("Enter a number: "))
if inp > 5:
value = "greater than five"
else:
value = "not greater than five"
print(value) # ✅ works — value was created in one of the branches
⚠️ Danger — variable may not exist
if inp > 5:
value = "greater than five"
print(value) # ❌ NameError if inp <= 5 — value was never created
Block variables are NOT accessible inside a function
value = "hello" # global
def foo():
print(value) # ✅ can access global value
# BUT a variable created inside a function block is not accessible outside
def bar():
if True:
result = 10
# result is not accessible here
4. Scope with Function Parameters
Parameters are local to the function. Reassigning a parameter does not change the variable outside.
def add_five(x):
x = x + 5 # only changes the local x
print(x) # → 15
x = 10
print(x) # → 10
add_five(x) # → 15
print(x) # → 10 (unchanged)
5. Scope + Mutability
For mutable objects (lists, dicts, sets), changes made inside a function do affect the original — because the parameter points to the same object.
def append_five(x):
x.append(5)
x = []
append_five(x)
print(x) # → [5] — original was modified!
Fix — copy the object to avoid modifying the original
def append_five(x):
x = x[:] # make a copy
x.append(5)
print(x) # → [5]
x = []
append_five(x)
print(x) # → [] — original untouched
This is the intersection of scope and mutability. Even though you can't reassign a global variable from inside a function, you can mutate a mutable object passed to it.
6. The global Keyword
Forces a variable inside a function to refer to the global variable instead of creating a new local one.
value = 5
def foo():
global value
value = 10 # modifies the GLOBAL value
foo()
print(value) # → 10
⚠️ Avoid using global
Using global is considered bad practice because:
- It creates hidden side effects — the function changes something outside itself
- It makes code hard to debug and reason about
- It's unpredictable when the same variable name is reused elsewhere
There is no situation in standard Python exercises that requires the
globalkeyword. Avoid it.
7. Scope Summary
| Location | Accessible inside function? | Accessible outside function? |
|---|---|---|
| Global variable | ✅ Yes | ✅ Yes |
| Local variable (in function) | ✅ Yes | ❌ No |
Block variable (if/for) |
✅ Yes (if created) | ✅ Yes (if created) |
| Parameter | ✅ Yes (local copy) | ❌ No |
Cheat Sheet
# Global accessible inside function
x = 10
def foo():
print(x) # ✅ works
# Local NOT accessible outside
def bar():
y = 5
print(y) # ❌ NameError
# Local shadows global (same name)
x = 10
def foo():
x = 99 # local x, doesn't change global
print(x) # → 99
print(x) # → 10
# Mutable object modified inside function
def modify(lst):
lst.append(1)
a = []
modify(a)
print(a) # → [1]
# Avoid mutation — copy first
def modify_safe(lst):
lst = lst[:]
lst.append(1)
# global keyword (avoid!)
val = 5
def foo():
global val
val = 10