5.4 Variable Scope (Local, Global, Nonlocal)

In Python, scope refers to the region of the code where a variable is accessible. Understanding variable scope is essential to avoid conflicts and errors in larger programs, as it determines the accessibility and lifespan of a variable. Variables can have different levels of scope: local, global, or nonlocal.

In this section, we’ll explore the concepts of local, global, and nonlocal scopes, how to work with them, and common use cases.


5.4.1 Local Scope

A variable defined inside a function has local scope, meaning it is accessible only within that function. Once the function finishes executing, the local variables are destroyed and cannot be accessed outside of the function.

Example:

def my_function():
    x = 10  # Local variable
    print(f"x inside function: {x}")

my_function()
# print(x)  # This would raise a NameError, as x is not accessible outside the function

Output:

x inside function: 10

In this example:

  • The variable x is defined inside the my_function() function, so it has local scope.
  • Attempting to access x outside the function would raise a NameError, as x is only available within the function.

5.4.2 Global Scope

A variable defined outside any function or block of code has global scope. Global variables can be accessed from anywhere in the program, including inside functions (unless shadowed by a local variable of the same name).

Example:

x = 20  # Global variable

def my_function():
    print(f"x inside function: {x}")

my_function()
print(f"x outside function: {x}")

Output:

x inside function: 20
x outside function: 20

In this example:

  • The variable x is defined outside the function, so it has global scope.
  • It is accessible both inside and outside the function.

5.4.3 Modifying Global Variables

You can modify global variables inside a function using the global keyword. Without the global keyword, attempting to modify a global variable inside a function will create a new local variable instead of changing the global variable.

Example without global:

x = 10  # Global variable

def my_function():
    x = 20  # Local variable (shadowing the global x)
    print(f"x inside function: {x}")

my_function()
print(f"x outside function: {x}")

Output:

x inside function: 20
x outside function: 10

In this case:

  • The global variable x remains unchanged because x = 20 inside the function creates a new local variable x, which shadows the global x within the function.

Example with global:

x = 10  # Global variable

def my_function():
    global x  # Refers to the global x
    x = 20    # Modifies the global x
    print(f"x inside function: {x}")

my_function()
print(f"x outside function: {x}")

Output:

x inside function: 20
x outside function: 20

In this case:

  • Using the global keyword allows the function to modify the global variable x.

5.4.4 Nonlocal Scope

The nonlocal keyword is used to modify variables in an enclosing (outer) function’s scope. This is useful when working with nested functions, where a variable is neither local to the inner function nor global.

  • Local Scope: Variables defined within a function.
  • Nonlocal Scope: Variables defined in an outer function that can be accessed and modified by an inner function.
  • Global Scope: Variables defined at the top level of the program.

Example of Nonlocal Scope:

def outer_function():
    x = 10  # Enclosing variable

    def inner_function():
        nonlocal x  # Refers to the variable in the outer_function's scope
        x = 20      # Modifies the enclosing variable
        print(f"x inside inner_function: {x}")

    inner_function()
    print(f"x inside outer_function: {x}")

outer_function()

Output:

x inside inner_function: 20
x inside outer_function: 20

In this example:

  • The variable x is defined in the enclosing scope (inside outer_function()).
  • The inner_function() uses the nonlocal keyword to modify x in the outer function’s scope.

5.4.5 LEGB Rule (Scope Resolution)

Python resolves variable names based on the LEGB rule, which stands for Local, Enclosing, Global, and Built-in. When a variable is referenced, Python searches for it in the following order:

  1. Local: The innermost scope, such as variables defined inside the current function.
  2. Enclosing: Variables in the enclosing function’s scope (in case of nested functions).
  3. Global: Variables defined at the top level of the program.
  4. Built-in: Python’s built-in names (e.g., print(), len(), etc.).

Example:

x = "global"

def outer_function():
    x = "enclosing"
    
    def inner_function():
        x = "local"
        print(f"x inside inner_function: {x}")  # Local scope

    inner_function()
    print(f"x inside outer_function: {x}")  # Enclosing scope

outer_function()
print(f"x in global scope: {x}")  # Global scope

Output:

x inside inner_function: local
x inside outer_function: enclosing
x in global scope: global

In this example:

  • The variable x is defined in three scopes: local (inside inner_function()), enclosing (inside outer_function()), and global.
  • Python follows the LEGB rule to resolve which x to use in each scope.

5.4.6 Summary

  • Local scope: Variables defined within a function are local and accessible only within that function.
  • Global scope: Variables defined outside any function are global and accessible from anywhere in the program. Global variables can be modified inside a function using the global keyword.
  • Nonlocal scope: Variables in an enclosing function’s scope can be accessed and modified inside a nested function using the nonlocal keyword.
  • LEGB rule: Python follows the LEGB (Local, Enclosing, Global, Built-in) rule to resolve variable names. It first checks the local scope, then the enclosing scope, followed by the global scope, and finally the built-in scope.

Understanding variable scope is crucial to avoid unintended behavior and to control where and how variables are accessed and modified in your Python programs.