Python
Understanding Python
Namespaces
A Deep Dive into Python’s Name Resolution
May 2, 2025
Source Code
PYTHON NAMESPACES
1. Understanding Python Namespaces
In Python, a namespace is a container that holds a mapping of names to objects.
Think of it as a dictionary where variable names are the keys and the objects
they refer to are the values. Understanding namespaces is crucial because they:
• Prevent naming conflicts by organizing names into hierarchical spaces
• Define the scope and lifetime of variables
• Help manage the visibility and accessibility of variables
2. Types of Namespaces
Python has several types of namespaces with different lifetimes:
• Built-in Namespace: Contains built-in functions and exceptions
• Global Namespace: Module-level variables and functions
• Local Namespace: Names inside functions
• Enclosing Namespace: Names in outer functions (for nested functions)
Let’s explore each type with practical examples:
2.1. Basic Namespace Example
How to Run:
Alejandro Sánchez Yalí
Software Developer | AI & Blockchain Enthusiast
www.asanchezyali.com
PYTHON NAMESPACES
• Save the code as 01_basic_namespaces.py
• Run: python3 01_basic_namespaces.py
1 # --- 01_basic_namespaces.py ---
2 """
3 Basic Namespaces in Python
4
5 This file demonstrates the fundamental concept of
namespaces in Python.
6 A namespace is a mapping from names to objects.
7 """
8
9 # The built-in namespace contains functions like print,
len, etc.
10 print("Built-in namespace example:")
11 print(f"Type of len function: {type(len)}")
12 print(f"ID of len function: {id(len)}")
13
14 # The global namespace of a module
15 x = 10
16 y = "hello"
Alejandro Sánchez Yalí
Software Developer | AI & Blockchain Enthusiast
www.asanchezyali.com
PYTHON NAMESPACES
17
18 print("\nGlobal namespace example:")
19 print(f"x = {x}, type: {type(x)}, id: {id(x)}")
20 print(f"y = {y}, type: {type(y)}, id: {id(y)}")
21
22 # Local namespace in a function with proper global
variable handling
23 def example_function():
24 # Declare x as global before using it
25 global x
26 z = 20 # Local variable
27 print("\nLocal namespace inside function:")
28 print(f"z = {z}, type: {type(z)}, id: {id(z)}")
29
30 # Now we can safely access and modify the global x
31 print(f"x from global namespace: {x}")
32 x = 30 # This modifies the global x
33 print(f"Modified global x: {x}")
34
35 # Call the function
36 print("\nBefore function call:")
37 print(f"Global x is: {x}")
Alejandro Sánchez Yalí
Software Developer | AI & Blockchain Enthusiast
www.asanchezyali.com
PYTHON NAMESPACES
38
39 example_function()
40
41 print("\nAfter function call:")
42 print(f"Global x is now: {x}") # Will show the modified
value
Key points about this example:
• Built-in functions like len live in the built-in namespace
• Variables defined at module level (x and y) are in the global namespace
• Variables defined inside functions (z) are in the local namespace
• The global keyword allows modifying global variables from inside func-
tions
2.2. Nested Scopes and the nonlocal Keyword
Let’s explore how Python handles nested function scopes and the usage of the
nonlocal keyword:
How to Run:
• Save the code as 02_nested_scopes.py
• Run: python3 02_nested_scopes.py
Alejandro Sánchez Yalí
Software Developer | AI & Blockchain Enthusiast
www.asanchezyali.com
PYTHON NAMESPACES
1 # --- 02_nested_scopes.py ---
2 """
3 Nested Scopes and the nonlocal Keyword
4
5 This file demonstrates how Python handles nested function
scopes
6 and the usage of the ’nonlocal’ keyword for modifying
variables
7 in outer (but not global) scopes.
8 """
9
10 def scope_test():
11 def do_local():
12 spam = "local spam" # Creates a new local variable
13
14 def do_nonlocal():
15 nonlocal spam # Refers to spam in scope_test
16 spam = "nonlocal spam"
17
18 def do_global():
Alejandro Sánchez Yalí
Software Developer | AI & Blockchain Enthusiast
www.asanchezyali.com
PYTHON NAMESPACES
19 global spam # Refers to global spam
20 spam = "global spam"
21
22 # Initialize spam in scope_test’s scope
23 spam = "test spam"
24 print("Initial value:", spam)
25
26 do_local()
27 print("After local assignment:", spam)
28
29 do_nonlocal()
30 print("After nonlocal assignment:", spam)
31
32 do_global()
33 print("After global assignment:", spam)
34
35 print("Starting scope test\n")
36 scope_test()
37 print("\nIn global scope:", spam) # Will print the global
spam value
This example demonstrates:
• Local assignments do not affect variables in outer scopes
Alejandro Sánchez Yalí
Software Developer | AI & Blockchain Enthusiast
www.asanchezyali.com
PYTHON NAMESPACES
• nonlocal allows modifying variables in the nearest enclosing scope
• global allows modifying variables in the global scope
• Each function has its own local namespace
2.3. Class and Instance Namespaces
Python also has special namespaces for classes and instances. Let’s explore how
they work:
How to Run:
• Save the code as 03_class_namespaces.py
• Run: python3 03_class_namespaces.py
1 # --- 03_class_namespaces.py ---
2 """
3 Class and Instance Namespaces
4
5 This file demonstrates how Python handles namespaces in
classes,
6 showing the difference between class variables (shared by
all instances)
7 and instance variables (unique to each instance).
Alejandro Sánchez Yalí
Software Developer | AI & Blockchain Enthusiast
www.asanchezyali.com
PYTHON NAMESPACES
8 """
9
10 class Dog:
11 # Class variable - shared by all instances
12 species = "Canis familiaris"
13
14 # Class variable containing a mutable object (for
demonstration)
15 tricks = [] # Shared by all dogs!
16
17 def __init__(self, name):
18 # Instance variables - unique to each instance
19 self.name = name
20 self.individual_tricks = [] # Better - each dog
has its own list
21
22 def add_shared_trick(self, trick):
23 # Modifies the class variable (affects all dogs)
24 Dog.tricks.append(trick)
25
26 def add_individual_trick(self, trick):
27 # Modifies the instance variable (affects only
Alejandro Sánchez Yalí
Software Developer | AI & Blockchain Enthusiast
www.asanchezyali.com
PYTHON NAMESPACES
this dog)
28 self.individual_tricks.append(trick)
29
30 # Create two dogs
31 print("Creating two dogs...\n")
32 fido = Dog("Fido")
33 buddy = Dog("Buddy")
34
35 # Demonstrate class variable sharing
36 print("Class variable demonstration:")
37 print(f"Fido’s species: {fido.species}")
38 print(f"Buddy’s species: {buddy.species}")
39
40 # Change the class variable
41 Dog.species = "Canis lupus familiaris"
42 print("\nAfter changing class variable:")
43 print(f"Fido’s species: {fido.species}")
44 print(f"Buddy’s species: {buddy.species}")
45
46 # Demonstrate instance variable independence
47 print("\nInstance variable demonstration:")
48 print(f"Fido’s name: {fido.name}")
Alejandro Sánchez Yalí
Software Developer | AI & Blockchain Enthusiast
www.asanchezyali.com
PYTHON NAMESPACES
49 print(f"Buddy’s name: {buddy.name}")
50
51 # Demonstrate the difference with mutable objects
52 print("\nShared tricks list (class variable):")
53 fido.add_shared_trick("roll over")
54 print(f"Fido’s tricks: {Dog.tricks}")
55 print(f"Buddy’s tricks: {buddy.tricks} # Same list!")
56
57 print("\nIndividual tricks lists (instance variables):")
58 fido.add_individual_trick("play dead")
59 buddy.add_individual_trick("fetch")
60 print(f"Fido’s individual tricks:
{fido.individual_tricks}")
61 print(f"Buddy’s individual tricks:
{buddy.individual_tricks}")
62
63 # Demonstrate attribute lookup order
64 print("\nAttribute lookup demonstration:")
65 buddy.species = "Changed for buddy" # Creates a new
instance variable
66 print(f"Fido’s species (from class): {fido.species}")
67 print(f"Buddy’s species (from instance): {buddy.species}")
Alejandro Sánchez Yalí
Software Developer | AI & Blockchain Enthusiast
www.asanchezyali.com
PYTHON NAMESPACES
68 print(f"Class species attribute: {Dog.species}")
Key points about class and instance namespaces:
• Class variables are shared among all instances
• Instance variables are unique to each instance
• Be cautious with mutable class variables
• Python looks up attributes first in the instance namespace, then in the class
namespace
3. Advanced Namespace Concepts: Closures and An-
notations
Python’s namespace system becomes even more powerful when working with
closures and type annotations. These advanced features demonstrate the flex-
ibility and sophistication of Python’s scoping rules.
3.1. Function Closures and Free Variables
A closure occurs when a nested function references variables from its enclosing
scope. The inner function "closes over" the variables it needs, preserving them
even after the outer function returns.
How to Run:
• Save the code as 04_closures_annotations.py
Alejandro Sánchez Yalí
Software Developer | AI & Blockchain Enthusiast
www.asanchezyali.com
PYTHON NAMESPACES
• Run: python3 04_closures_annotations.py
1 # --- 04_closures_annotations.py ---
2 """
3 Function Closures and Annotation Scopes
4
5 This file demonstrates Python’s closure mechanism and how
annotations
6 are handled in different scopes. It shows how free
variables are
7 captured and how annotations are evaluated.
8 """
9 from typing import Callable, List
10
11 def make_counter(start: int = 0) -> Callable[[], int]:
12 """Creates a counter function with its own private
state."""
13 count = start
14
15 def counter() -> int:
16 nonlocal count
Alejandro Sánchez Yalí
Software Developer | AI & Blockchain Enthusiast
www.asanchezyali.com
PYTHON NAMESPACES
17 current = count
18 count += 1
19 return current
20
21 return counter
22
23 def make_multiplier(factor: float) -> Callable[[float],
float]:
24 """Creates a function that multiplies its input by a
stored factor."""
25 # ’factor’ is a free variable captured by the closure
26 def multiplier(x: float) -> float:
27 return x * factor
28
29 return multiplier
30
31 # Demonstrate closure behavior
32 print("Closure demonstration:")
33 counter1 = make_counter(5)
34 counter2 = make_counter(10)
35
36 print(f"Counter 1: {counter1()}, {counter1()},
Alejandro Sánchez Yalí
Software Developer | AI & Blockchain Enthusiast
www.asanchezyali.com
PYTHON NAMESPACES
{counter1()}")
37 print(f"Counter 2: {counter2()}, {counter2()},
{counter2()}")
38
39 # Demonstrate multiple closures with the same free variable
40 print("\nMultiplier demonstration:")
41 double = make_multiplier(2)
42 triple = make_multiplier(3)
43
44 print(f"Double 5: {double(5)}")
45 print(f"Triple 5: {triple(5)}")
46
47 # Demonstrate late binding behavior
48 def create_functions() -> List[Callable[[], int]]:
49 """Demonstrates late binding behavior in closures."""
50 functions = []
51 for i in range(3):
52 def func(captured_i=i): # Use default argument
for early binding
53 return captured_i
54 functions.append(func)
55 return functions
Alejandro Sánchez Yalí
Software Developer | AI & Blockchain Enthusiast
www.asanchezyali.com
PYTHON NAMESPACES
56
57 print("\nLate binding demonstration:")
58 funcs = create_functions()
59 for f in funcs:
60 print(f"Function returns: {f()}")
61
62 # Demonstrate annotation scopes
63 def outer(x: ’TypeVar’) -> None:
64 y: ’TypeVar’ # Forward reference in annotation
65
66 class TypeVar:
67 pass
68
69 y = TypeVar() # This refers to the local TypeVar class
70 print(f"Type of y: {type(y).__name__}")
71
72 print("\nAnnotation scope demonstration:")
73 outer(None) # The ’TypeVar’ in the annotation is treated
as a string
This example demonstrates several advanced concepts:
• Each function call creates a new instance of the local variables
• Closures can "remember" values from the enclosing scope
Alejandro Sánchez Yalí
Software Developer | AI & Blockchain Enthusiast
www.asanchezyali.com
PYTHON NAMESPACES
• The nonlocal keyword is needed to modify enclosed variables
• Type annotations in closures follow special scoping rules
3.2. Key Insights About Closures
When working with closures in Python:
• Each function call creates a new instance of the local variables
• Closures can "remember" values from the enclosing scope
• The nonlocal keyword is needed to modify enclosed variables
• Type annotations in closures follow special scoping rules
3.3. Best Practices with Closures
When using closures in your code:
• Use closures to create functions with private state
• Be careful with mutable free variables
• Consider using default arguments for early binding when needed
• Document the closure’s behavior and any captured variables
Alejandro Sánchez Yalí
Software Developer | AI & Blockchain Enthusiast
www.asanchezyali.com
PYTHON NAMESPACES
4. Name Resolution Rules: LEGB
Python follows the LEGB rule when looking up names:
• Local: Names declared inside the current function
• Enclosing: Names in enclosing functions
• Global: Names declared at module level
• Built-in: Names in the built-in module
Python searches these namespaces in this order until it finds the name or raises
a NameError.
5. Best Practices
When working with namespaces in Python:
• Use global sparingly - it can make code harder to understand
• Prefer passing values as arguments and returning results
• Be careful with mutable class variables
• Use clear and descriptive names to avoid confusion
• Document when you need to use global or nonlocal
Alejandro Sánchez Yalí
Software Developer | AI & Blockchain Enthusiast
www.asanchezyali.com
PYTHON NAMESPACES
6. References
• Python Documentation. (2025). Python Scopes and Namespaces. Link
• Python Documentation. (2025). The global statement. Link
• Python Documentation. (2025). The nonlocal statement. Link
• Lutz, M. (2023). Learning Python, 6th Edition. O’Reilly Media.
• This article was edited and written in collaboration with AI. If you find any
inconsistencies or have suggestions for improvement, please don’t hesi-
tate to open an issue in our GitHub repository or reach out directly.
7. Explore More Python Concepts
Enjoyed This Content?
Don’t miss my other Python articles:
Python Decorators: A Comprehensive Guide
Learn how to write and use decorators in Python to enhance your
functions and classes with additional functionality.
Alejandro Sánchez Yalí
Software Developer | AI & Blockchain Enthusiast
www.asanchezyali.com
Feedback
Found this helpful?
Save, comment and share
May 2, 2025