Skip to content

Python3 Namespace and Scope

First, let’s look at a passage from the official documentation:

A namespace is a mapping from names to objects. Most namespaces are currently implemented as Python dictionaries.

A namespace is a mapping from names to objects, and most namespaces are implemented through Python dictionaries.

Namespaces provide a way to avoid name conflicts in projects. Each namespace is independent and unrelated, so there cannot be duplicate names within a single namespace, but different namespaces can have duplicate names without any impact.

Let’s take an example from a computer system: a folder (directory) can contain multiple folders. Each folder cannot have files with the same name, but files in different folders can have the same name.

Generally, there are three types of namespaces:

  • Built-in names, names built into the Python language, such as function names like abs, char, and exception names like BaseException, Exception, etc.
  • Global names, names defined in a module, recording the module’s variables, including functions, classes, other imported modules, and module-level variables and constants.
  • Local names, names defined in a function, recording the function’s variables, including function parameters and locally defined variables. (Also those defined in classes)

Namespace lookup order:

Suppose we want to use the variable runoob, then Python’s search order is: local namespace -> global namespace -> built-in namespace.

If the variable runoob cannot be found, it will give up the search and raise a NameError exception:

NameError: name 'runoob' is not defined.

Namespace lifecycle:

The lifecycle of a namespace depends on the scope of the object. If the object execution is complete, the lifecycle of that namespace ends.

Therefore, we cannot access objects from an inner namespace from an outer namespace.

# var1 is a global name
var1 = 5
def some_func(): 
  
    # var2 is a local name
    var2 = 6
    def some_inner_func(): 
  
        # var3 is an embedded local name
        var3 = 7

As shown in the following diagram, the same object name can exist in multiple namespaces.


A scope is a textual region of a Python program where a namespace is directly accessible. “Directly accessible” here means that an unqualified reference to a name attempts to find the name in the namespace.

A scope is a textual region of a Python program where a namespace is directly accessible.

In a Python program, directly accessing a variable will search from the innermost to the outermost scope until it is found, otherwise an undefined error will be reported.

In Python, program variables are not accessible from everywhere. Access permissions are determined by where the variable is assigned.

The scope of a variable determines which part of the program can access which specific variable name.

Python has 4 types of scopes:

There are four scopes:

  • L (Local): The innermost layer, containing local variables, such as inside a function/method.
  • E (Enclosing): Contains non-local and non-global variables. For example, with two nested functions, if a function (or class) A contains a function B, then for names in B, the scope in A is nonlocal.
  • G (Global): The outermost layer of the current script, such as the global variables of the current module.
  • B (Built-in): Contains built-in variables/keywords, searched last.

LEGB Rule (Local, Enclosing, Global, Built-in): The order in which Python looks up variables is: L –> E –> G –> B.

  1. Local: The local scope of the current function.
  2. Enclosing: The scope of the outer function containing the current function (if there are nested functions).
  3. Global: The global scope of the current module.
  4. Built-in: Python’s built-in scope.

If not found locally, it will search in the enclosing scope (e.g., closures), then in the global scope if not found, and finally in the built-in scope.

g_count = 0  # Global scope
def outer():
    o_count = 1  # In the function outside the closure function
    def inner():
        i_count = 2  # Local scope

The built-in scope is implemented through a standard module called builtin, but this variable name itself is not placed in the built-in scope, so you must import this file to use it. In Python 3.0, you can use the following code to see what variables are predefined:

>>> import builtins
>>> dir(builtins)

In Python, only modules, classes, and functions (def, lambda) introduce new scopes. Other code blocks (such as if/elif/else/, try/except, for/while, etc.) do not introduce new scopes. This means that variables defined inside these statements can also be accessed from outside, as shown in the following code:

>>> if True:
...  msg = 'I am from Runoob'
... 
>>> msg
'I am from Runoob'
>>> 

In the example, the msg variable is defined inside the if statement block, but it can still be accessed from outside.

If msg is defined inside a function, it becomes a local variable and cannot be accessed from outside:

>>> def test():
...     msg_inner = 'I am from Runoob'
... 
>>> msg_inner
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'msg_inner' is not defined
>>> 

The error message indicates that msg_inner is undefined and cannot be used because it is a local variable that can only be used within the function.

Variables defined inside a function have a local scope, while those defined outside a function have a global scope.

Local variables can only be accessed within the function where they are declared, while global variables can be accessed throughout the entire program.

Variables declared inside a function are only effective within the function’s internal scope. When the function is called, these internal variables are added to the function’s internal scope and do not affect variables with the same name outside the function, as shown in the following example:

#!/usr/bin/python3
 
total = 0 # This is a global variable
# Writable function description
def sum( arg1, arg2 ):
    # Return the sum of two parameters.
    total = arg1 + arg2 # total is a local variable here.
    print ("Inside the function, it is a local variable: ", total)
    return total
 
# Call the sum function
sum( 10, 20 )
print ("Outside the function, it is a global variable: ", total)

Output of the above example:

Inside the function, it is a local variable:  30
Outside the function, it is a global variable:  0
  1. Global Variables: Variables defined outside a function can be accessed throughout the entire file. Variables defined outside a function are visible to all functions, unless a local variable with the same name is defined inside the function.
x = 10  # Global variable

def my_function():
    print(x)  # Can access the global variable x

my_function()  # Output 10
  1. Local Variables: Variables defined inside a function are only effective within the function and cannot be accessed from outside. Local variables have higher priority than global variables, so if a local variable and a global variable have the same name, the function will use the local variable.
def my_function():
    x = 5  # Local variable
    print(x)  # Access the local variable x

my_function()  # Output 5
print(x)  # Error: NameError: name 'x' is not defined

When an inner scope wants to modify variables in an outer scope, the global and nonlocal keywords are used.

The following example modifies the global variable num:

#!/usr/bin/python3
 
num = 1
def fun1():
    global num  # Need to use the global keyword to declare
    print(num) 
    num = 123
    print(num)
fun1()
print(num)

Output of the above example:

1
123
123

If you want to modify variables in a nested scope (enclosing scope, outer non-global scope), you need the nonlocal keyword, as shown in the following example:

#!/usr/bin/python3
 
def outer():
    num = 10
    def inner():
        nonlocal num   # nonlocal keyword declaration
        num = 100
        print(num)
    inner()
    print(num)
outer()

Output of the above example:

100
100

There is also a special case. Suppose the following code is run:

#!/usr/bin/python3
 
a = 10
def test():
    a = a + 1
    print(a)
test()

The above program execution produces the following error message:

Traceback (most recent call last):
  File "test.py", line 7, in <module>
    test()
  File "test.py", line 5, in test
    a = a + 1
UnboundLocalError: local variable 'a' referenced before assignment

The error message is a local scope reference error, because a in the test function uses the local one, which is undefined and cannot be modified.

Modify a to be a global variable:

#!/usr/bin/python3
 
a = 10
def test():
    global a
    a = a + 1
    print(a)
test()

The execution output is:

11

You can also pass it through function parameters:

#!/usr/bin/python3
 
a = 10
def test(a):
    a = a + 1
    print(a)
test(a)

The execution output is:

11
  • Global variables are defined outside a function and can be accessed throughout the entire file.
  • Local variables are defined inside a function and can only be accessed within the function.
  • Use global to modify global variables within a function.
  • Use nonlocal to modify variables of the outer function within a nested function.