Namespace and Scope in Python: Understand Where Names Live
Introduction
In this chapter, you will learn namespace and scope in Python, two concepts that explain how variable names are stored and resolved. Understanding this helps you avoid many confusing bugs, especially in functions and nested functions. Once you master scope rules, your code becomes safer, cleaner, and easier to debug.
Prerequisites
- Python
3.10+installed - Basic understanding of variables, functions, and classes
- Ability to run
.pyfiles in terminal or IDE
What Is a Namespace
A namespace is a mapping between names and objects.
Examples of namespaces:
- built-in namespace (
len,print,str, ...) - global namespace (module-level names)
- local namespace (inside functions)
You can think of namespace as a "name dictionary" Python uses to find values.
What Is Scope
Scope is the region where a name can be accessed directly.
Main scope levels in Python:
- local scope
- enclosing scope
- global scope
- built-in scope
This lookup order is often called LEGB:
- Local
- Enclosing
- Global
- Built-in
1) Local and Global Scope
# Global variable
course = "Python Basics"
def show_info():
# Local variable
lesson = "Namespace and Scope"
print(course) # accessible
print(lesson) # accessible
show_info()
# print(lesson) # NameError: lesson is local onlylesson exists only inside show_info().
2) Global Keyword
Use global when you need to modify a global variable inside a function.
# Global counter
count = 0
def increase():
global count
count += 1
increase()
increase()
print(count) # 2Without global, assignment creates a new local variable instead.
3) Enclosing Scope and nonlocal
nonlocal is used in nested functions to modify variables in enclosing (outer function) scope.
def outer():
value = 10
def inner():
nonlocal value
value += 5
print("Inner value:", value)
inner()
print("Outer value:", value)
outer()This updates value in outer() scope, not global scope.
Tip
When to Use nonlocal
Use nonlocal in closures when inner functions must update outer function state.
4) Built-in Namespace
Built-in names are always available unless shadowed.
print(len([1, 2, 3])) # built-in lenAvoid reusing built-in names:
# Bad practice: shadowing built-in name
len = 100
# print(len([1, 2])) # This will fail because len is no longer function here5) LEGB Lookup Demo
This example shows how Python resolves a name.
x = "global_x"
def outer():
x = "enclosing_x"
def inner():
x = "local_x"
print(x) # local_x
inner()
print(x) # enclosing_x
outer()
print(x) # global_xPython picks the nearest available scope first.
6) Real Mini Example: Score Tracker with Closure
This example uses enclosing scope and nonlocal to maintain state.
def make_score_tracker():
# Enclosing scope variable
total = 0
count = 0
def add_score(score):
nonlocal total, count
total += score
count += 1
avg = total / count
print(f"Added: {score}, Current average: {avg:.2f}")
return add_score
# Create tracker function
tracker = make_score_tracker()
# Update scores over time
tracker(90)
tracker(80)
tracker(95)This is a practical closure pattern for lightweight state management.
Warning
Avoid overusing global variables in larger projects.
Too many globals make code harder to test and maintain.
Common Beginner Mistakes
Mistake 1: Expecting Local Variables Outside Functions
Local names are destroyed after function execution ends.
Mistake 2: Forgetting global or nonlocal for Assignment
Assignment in inner scopes creates local variables unless explicitly declared.
Mistake 3: Shadowing Built-ins
Using names like list, str, or len as variable names can break expected behavior.
Surprise Practice Challenge
Build a "Study Session Counter":
- Create function
make_session_counter() - Inside, keep
sessionsandtotal_minutesin enclosing scope - Return inner function
add_session(minutes) - Use
nonlocalto update state - Print total sessions and average minutes after each update
If you finish this, you understand scope deeply enough to use closures confidently.
FAQ
What is the difference between namespace and scope?
Namespace is where names are stored; scope is where names are visible/accessed directly.
Should I avoid global completely?
Not completely, but use it carefully. Prefer passing values and returning results in most cases.
Is nonlocal the same as global?
No. nonlocal targets enclosing function scope, while global targets module-level scope.
Why is LEGB important?
It explains exactly where Python looks for names, which helps debug variable-related issues quickly.