python

Understanding Python Variables: Namespaces and Variable Scope

A practical guide to Python namespaces and the LEGB rule for variable scope, with global and nonlocal examples

I’ve used Python throughout my career, and I still see developers trip over where a variable actually lives. This post covers namespaces and variable scope: how Python stores variables, and where each one is visible in your code.

A namespace is where a name lives; scope is where you can see it.

What is a namespace?

A namespace is a container that holds a set of identifiers: variable names, function names, class names, and more. Each identifier maps to an object in memory. Think of it as a dictionary where the keys are the names and the values are the objects they point to.

Unique naming system: namespaces keep names from colliding. You can have a function named calculate in one namespace and a different function with the same name in another namespace, with no conflict.

Lifetime of a namespace: a namespace exists as long as its scope does. Once that scope ends, the namespace is discarded and every name defined in it becomes unbound.

Types of namespaces

Python creates and deletes several kinds of namespaces at different times:

  1. Built-in namespace: holds Python’s built-in functions and exceptions. Created when the interpreter starts up.
  2. Global (module) namespace: specific to a module or script. Created when the module is imported or the script runs.
  3. Enclosing (function) namespace: exists for nested functions, chaining function namespaces from innermost to outermost.
  4. Local namespace: created when a function is called and discarded once it finishes running.

Variable scope

Scope defines the region of code where a variable can be accessed or modified. Python has four scopes:

  1. Local (L): inside the current function.
  2. Enclosing (E): inside enclosing functions.
  3. Global (G): at the top level of the module.
  4. Built-in (B): in the built-in namespace.

Together, these form the LEGB rule, which Python follows when it resolves a variable name.

Scope in practice

python
x = 10  # global variable

def outer_function():
    y = 5  # enclosing variable
    
    def inner_function():
        z = 3 # local var
        
        print(x, y, z)
    
    inner_function()

outer_function()

When inner_function is called, it reads:

  • z from its local scope
  • y from the enclosing scope of outer_function
  • x from the global scope

The global and nonlocal keywords

To modify global or enclosing variables within a function, Python provides the global and nonlocal keywords:

python
x = 10

def modify_global():
    global x
    x = 20

def outer_function():
    y = 5
    
    def modify_enclosing():
        nonlocal y
        y = 15
    
    modify_enclosing()
    print(y)

modify_global()
outer_function()
print(x)

This code outputs:

bash
1520

The global keyword tells Python you mean the global x; nonlocal tells it you mean the y from the enclosing function.

Avoid variable shadowing

If a local variable shares a name with a global variable or a built-in, it shadows that global or built-in:

python
x = 10

def shadow_example():
    x = 5
    print(x)

shadow_example()  # Outputs: 5
print(x)  # Outputs: 10

Shadowing can cause unexpected behavior, so avoid reusing the same name across different scopes.

Putting it together

Namespaces and variable scope are the foundation of how Python manages and accesses data. Understanding them helps you write clearer, more predictable code and avoid common pitfalls. Remember the LEGB rule, watch for shadowing, and use global and nonlocal only when you actually need them.

Happy coding.



If you liked this post, you can support my work by buying me a coffee. Your support means a lot. If you share this on Twitter, tag me @muhammad_o7.

You can also book a 30-minute call with me if you’d like to talk, or if you have an open source project you’d like me to contribute to.

Want new posts in your inbox? Subscribe by email or follow the RSS feed.