Understanding Python Scopes

Introduction

A scope is the extent of visibility and accessibility of named entities such as variables, functions, and classes, within a program. It determines where in your code you can access a particular name or identifier. There are three types of Python scopes: build-in, global, and local.

Built-in Scope

The built-in scope in Python refers to names that are internal to the Python language and are always available. These names include built-in functions (e.g., print(), len()), built-in variables (e.g., __name__), built-in exceptions (e.g., ZeroDivisionError, TypeError), and other built-in objects (e.g., True, False, None).

You can access built-in names from anywhere in your code without explicitly defining or importing them.

Example:

def print_length(obj):
    print(f"The length is {len(obj)}.")

print_length([1, 2, 3, 4, 5])

Output:

The length is 5.

The example above defines the function print_length() (lines 1-2), which prints the length of a given object, such as the list used here (line 4). It uses the functions print() and len() (line 2), which are built-in Python functions and can be accessed directly.

Global Scope

Names defined at the top level of a Python file, i.e. module or script, have a global scope. Global names are accessible from anywhere within the module or script where they are defined.

The word “global” for this scope is a bit misleading because it does not span everything, as its meaning implies. Different Python files have separate global scopes. For items to be accessed and used across different files, they must be imported.

Example:

global_var = 10  # Global variable

def global_function():
    print(f"The value of the global variable is {global_var}.")

class GlobalClass:
    pass  # Do nothing 
    
global_function()
my_obj = GlobalClass()

Output:

The value of the global variable is 10.

In the example above, global_var, global_function(), and GlobalClass are defined at the global scope (lines 1,3, and 6, resp.) and can be accessed from any part of the file. The global_function() function accesses global_var in order to print it (line 4), and is itself used toward the bottom of the file (line 9). The GlobalClass class is used at the end (line 10).

Local Scope

Local scope in Python refers to names defined within a specific function. These names are only accessible inside that function are not visible elsewhere.

Example:

def my_function():
    local_var = 20 
    print("Local variable:", local_var)

my_function() 
# local_var is unavailable here

Output:

Local variable: 20

In the above example, local_var is defined within the my_function() function (line 2), It is therefore a local variable and can only be accessed within my_function().

If you attempt to access a local variable outside its scope, you’ll receive an error.

Example:

def my_function():
    local_var = 20 
    print("Local variable:", local_var)

print(local_var)
...
NameError: name 'local_var' is not defined

The example above defines the same my_function() from before and attempts to access the local variable it defines, local_var (line 5). The result is a NameError exception.

If you assign a global variable of the same name as a local variable, it will be a different variable not associated with the local one.

Example:

def my_function():
    var = 20 
    print("Local variable:", var)

var = 10
my_function()
print("Global variable:", var)

Output:

Local variable: 20
Global variable: 10

The example above defines my_function() again. It’s the same my_function() as previously defined, except that this time its local variable is named var instead of local_var (line 2). The script assigns a variable of the same name, var, in the global scope with a value of 10 (line 5). The local var is assigned the value 20 within the function (line 2) when it executes (line 6). When the global var is printed (line 7), the output is 10, even though a local variable of the same name was assigned 20 before.

Nested Local Scopes in Inner Functions

As you learned in the previous section, a function creates a local scope for names defined inside it. This carries over to inner function (i.e. functions defined within other functions) to create the concept of nested local scopes with a few simple rules.

Here are rules of nested scopes:

  1. Names defined within an inner function are confined to its local scope and are unavailable to outer functions.
  2. Names defined within an outer function are accessible in inner functions it defines.
  3. An inner function is only accessible in the local scope of the enclosing outer function.

Example:

def outer_function():
    outer_var = 10

    def inner_function():
        inner_var = 20
        print("outer_var from inner_function():", outer_var)
        print("inner_var from inner_function():", inner_var)
    
    inner_function()
    # inner_var is unavailable here

outer_function()
# inner_function() is unavailable here

Output:

outer_var from inner_function(): 10
inner_var from inner_function(): 20

The example above defines the variable outer_var in the outer_function() function (line 2), and inner_var in the inner_function() function (line 5). Both variables are accessed and used in the inner function inner_function() (lines 6 and 7). However, attempts to access inner_var in outer_function() or inner_function() in the global file scope will both result in errors.

Hierarchy of Python Scopes

When you refer to a name within Python code, it will look for it within the scopes in the following order:

  1. Local scope (and nested local scopes from innermost to outermost)
  2. Global scope
  3. Built-in scope

This creates a hierarchy of nested scopes from the most constrained inner local to the most widely available build-in scope. In case there are entities with the same name in different scopes, Python will reference the first one it finds in the hierarchy.

Summary & Reference for Python Scopes

Python scopes determine the visibility and accessibility of named entities such as variables, functions, and classes within a program. There are three types of scopes: built-in, global, and local.


The built-in scope in Python refers to names that are internal to the Python language and are always available without the need for an import, e.g. print(), __name__, True, False, ZeroDivisionError.

def print_hello():
    print("Hello")  # print() is accessed from the built-in scope

Names defined at the top level of a Python file have a global scope. Global names are accessible from anywhere within the module or script where they are defined. However, different Python files have separate global scopes.

global_var = 10

def global_function():
    print(f"The value of the global variable is {global_var}.")  
    # global_var is accessed from the global scope of this file

global_function()

Local scope in Python refers to names defined within a specific function. These names are only accessible within that function are not visible outside of it.

def my_function():
    local_var = 20  # local_var is in the local scope and only accessible inside my_function()
    print("Local variable:", local_var)

my_function() 

Inner functions create nested local scopes that adhere to the following rules:

  1. Names defined within an inner function are confined to its local scope and are unavailable to outer functions.
  2. Names defined within an outer function are accessible in inner functions it defines.
  3. An inner function is only accessible in the local scope of the enclosing outer function.
def outer_function():
    outer_var = 10  
    # outer_var is accessible in outer_function() and its inner function, inner_function()

    def inner_function():
        inner_var = 20   
        # inner_var is accessible in inner_function(), but not in outer_function()
    
    inner_function()
    # inner_var is unavailable here

outer_function()

When you refer to a name in your program, Python will look for it within the scopes in the following order:

  1. Local scope (and nested local scopes from innermost to outermost)
  2. Global scope
  3. Built-in scope

In case there are entities with the same name in different scopes, Python will reference the first one it finds in the hierarchy above.