AiTechWorlds
AiTechWorlds
Here's a puzzle. A colleague in your office uses the name "Mike" when referring to the IT guy. You say "Mike" and mean your brother. Same word, completely different person — depending on context.
Variables in Python work the same way. Where a variable is defined determines where it can be used. This concept is called scope.
When you create a variable inside a function, it only exists within that function:
def make_greeting():
message = "Good morning!" # LOCAL variable
print(message)
make_greeting()
print(message) # NameError: name 'message' is not defined
Output:
Good morning!
NameError: name 'message' is not defined
The variable message was born when make_greeting() started running and ceased to exist the moment the function finished. Outside the function, it's gone.
This is a feature, not a bug. Imagine if every variable in every function you called cluttered your program permanently. Your code would be impossible to manage.
Variables created outside any function exist in the global scope. They're accessible from anywhere in the file:
website_name = "AiTechWorlds" # GLOBAL variable
def display_header():
print(f"Welcome to {website_name}") # Can READ global variable
def display_footer():
print(f"© 2026 {website_name}") # Can READ global variable
display_header()
display_footer()
Output:
Welcome to AiTechWorlds
© 2026 AiTechWorlds
Both functions can read the global variable. No problem there.
Here's where many beginners get confused:
count = 0
def increment():
count = count + 1 # This causes an error!
print(count)
increment()
Output:
UnboundLocalError: local variable 'count' referenced before assignment
Wait — count exists! Why can't the function use it?
When Python sees count = count + 1 inside a function, it assumes count is a local variable (because you're assigning to it). But then it tries to read count on the right side before it's been defined locally. Contradiction — hence the error.
global KeywordTo tell Python "I want to modify the global count, not create a new local one," use the global keyword:
count = 0
def increment():
global count # "I'm talking about the global count"
count = count + 1
print(f"Count is now: {count}")
increment()
increment()
increment()
print(f"Final count: {count}")
Output:
Count is now: 1
Count is now: 2
Count is now: 3
Final count: 3
Now the function modifies the actual global variable. But hold on — should you use global freely?
global (Most of the Time)# BAD practice — hard to track and debug
user_score = 0
user_lives = 3
def player_dies():
global user_score, user_lives
user_lives -= 1
user_score -= 50
def player_wins_level():
global user_score
user_score += 100
As programs grow, functions that modify global variables become a debugging nightmare. You call a function and suddenly something elsewhere breaks — but where? Which function changed it?
Better approach: pass values in and return values out:
# GOOD practice — clear, predictable, testable
def player_dies(lives, score):
return lives - 1, score - 50
def player_wins_level(score):
return score + 100
# The game state is explicit and controllable
lives = 3
score = 0
score = player_wins_level(score)
lives, score = player_dies(lives, score)
print(f"Lives: {lives}, Score: {score}")
The function doesn't secretly change anything. Everything is explicit.
Python looks up variable names in this order:
| Level | Stands For | Where |
|---|---|---|
| L | Local | Inside the current function |
| E | Enclosing | Inside any containing function (nested functions) |
| G | Global | At the top level of the file |
| B | Built-in | Python's built-in names (print, len, etc.) |
x = "global" # Global
def outer():
x = "enclosing" # Enclosing
def inner():
x = "local" # Local
print(x) # Finds local first → prints "local"
inner()
print(x) # Finds enclosing → prints "enclosing"
outer()
print(x) # Finds global → prints "global"
Output:
local
enclosing
global
Each scope is its own layer. Python searches from inside out, stopping at the first match.
This shows proper scope usage — global state managed through functions that take and return values:
total_enrolled = 0 # Global — tracks all-time count
def enroll_student(student_list, name, grade):
"""Add a student and return updated list and new count."""
global total_enrolled
student_list.append({"name": name, "grade": grade})
total_enrolled += 1
print(f"✓ Enrolled: {name} (Grade {grade})")
return student_list
def display_roster(student_list, class_name):
"""Display all students — reads only, no modification."""
print(f"\n--- {class_name} Roster ---")
if not student_list:
print(" No students enrolled yet.")
return
for i, student in enumerate(student_list, 1):
print(f" {i}. {student['name']} — Grade {student['grade']}")
print(f" Total: {len(student_list)} students")
# Running the program
class_10 = []
class_11 = []
class_10 = enroll_student(class_10, "Alice", 10)
class_10 = enroll_student(class_10, "Bob", 10)
class_11 = enroll_student(class_11, "Charlie", 11)
class_10 = enroll_student(class_10, "Diana", 10)
display_roster(class_10, "Class 10")
display_roster(class_11, "Class 11")
print(f"\nAll-time enrolled: {total_enrolled}")
Output:
✓ Enrolled: Alice (Grade 10)
✓ Enrolled: Bob (Grade 10)
✓ Enrolled: Charlie (Grade 11)
✓ Enrolled: Diana (Grade 10)
--- Class 10 Roster ---
1. Alice — Grade 10
2. Bob — Grade 10
3. Diana — Grade 10
Total: 3 students
--- Class 11 Roster ---
1. Charlie — Grade 11
Total: 1 students
All-time enrolled: 4
Notice: total_enrolled uses global because it genuinely represents a program-wide counter. The individual class lists are passed as parameters — no global needed.
global keyword to modify a global variable from inside a functionScope exists to keep programs organized and predictable. When a function only uses its parameters and local variables, you can understand it in isolation — without needing to know what the rest of the program is doing.
Get this course's notes on Telegram!
Free cheat sheets, summaries & practice exercises