Python Variable Scope

In Python, variable scope determines where a variable can be accessed or modified within a program. Python follows the LEGB to resolve variable names.

The LEGB Rule

Python searches for variables in this order:

  • Local – Inside the current function.
  • Enclosing – In enclosing functions (for nested functions).
  • Global – At the module level.
  • Built-in – Python’s built-in names.

Local Scope

Variable defined inside a function are local to that function and cannot be accessed from outside of it.

For example:

def my_func():
    x = 10 # Local Scope
    print(x)

my_func() # Output: 10

If you try to access the variable outside of the function, Python raises an error.

def my_func():
    x = 10 # Local Scope
    print(x)

my_func() # Output: 10

# Attempting to access x outside of function
print(x) # NameError: name 'x' is not defined

Enclosing Scope

This scope applies to nested functions. When a function is defined inside another function, the inner function can access variables in the outer (enclosing) function.

For example:

def outer_func():
    x = "outer" # Enclosing scope
    
    def inner_func():
        # Python first looks for x in in the local scope, doesn't find it, 
        # then searches the enclosing scope
        print(x)
    
    inner_func()

outer_func() # Output: outer

In this example, the function outer_func() is defined. Inside this function, a variable x is created and assigned the value "outer". Then, another function inner_func() is defined inside outer_func().

The inner_func() function contains a print(x) statement. After defining inner_func(), outer_func() calls it.

When outer_func() is called, it creates the variable x and the calls inner_func(). While executing inner_func(), Python encounters print(x) statement and looks for the variable x. Python first checks the local scope of inner_func(), doesn’t find it, and then checks the enclosing scope of outer_func(), where x is found.

As a result, the value "outer" is printed.

Local Variable in Inner Function

When the inner function defines a variable with the same name as in the enclosing function, it overrides the outer variable within its own scope.

For example:

def outer_func():
    x = "outer" # Enclosing scope variable

    def inner_func():
        x = "inner" # Local variable to inner_func (shadows outer x)
        print(x) # Prints the local variable 'x' of inner_func
    
    inner_func() # Calls inner_func
    print(x)  # Still uses outer_func's x (unchanged)

outer_func() # Calls outer_func

Output:

inner
outer

In this example, outer_func() defines a variable x with the value "outer".

Inside inner_func(), a new variable x is assigned the value "inner". This local variable shadows the x defined in outer_func() within its own scope but doesn’t replace or modify it.

As a result, when print(x) is executed inside inner_func(), Python uses the inner variable, and the output is "inner".

After calling inner_func(), I have printed x to show that its value in the enclosing scope of outer_func() is still "outer".

The nonlocal Keyword

The nonlocal keyword allows you to modify the variable in the enclosing scope (the outer function). Without nonlocal keyword, any assignment in the inner function would create a new local variable, leaving the outer variable unchanged.

For example:

def outer_func():
    x = "outer" # Enclosing scope variable

    def inner_func():
        nonlocal x # Tells Python to use x from the outer_func
        x = "inner" # Modify the outer variable x
        print(x) # Prints the modified value of x
    
    inner_func() # Calls inner_func
    print(x)  # Print x again to show that it was changed by inner_func

outer_func() # Calls outer_func

Ouput:

inner
inner

In this example, outer_func() defines a variable x with the value "outer".

Inside inner_func(), the statement nonlocal x tells Python to use the variable x from the enclosing scope (outer_func), instead of creating a new local variable. Then x is assigned the value "inner", which modifies the x in outer_func‘s scope.

When print(x) is executed inside inner_func(), it prints "inner".

After calling inner_func(), printing x in outer_func() also prints "inner", showing that the value of x in the enclosing scope was changed by inner_func().

Global Scope

Variables defined at the top level of a script or module are considered global and can be accessed from anywhere within the code, including inside functions.

For example:

x = "global" # Global scope

def my_func():
    print(x) # Accessible here

my_func()
print(x)  # Also accessible here

Output:

global
global

Local Variable in Function

When a function defines a variable with the same name as a global variable, it shadows the global variable within the function’s local scope, without changing the global variable itself.

For example:

x = "global" # Global variable

def my_func():
    x = "local" # Local variable
    print(x)  # Prints the local variable

my_func() # Calls the function my_func
print(x)   # Prints the global varaible

Output:

local
global

In this example, a variable x is defined at the global level with the value "global".

Inside my_func(), a new variable x is assigned the value "local". This variable is local to the function and shadows the global x within the function’s scope, but it does not change the global variable.

As a result, when print(x) is executed inside my_func(), Python uses the local variable, and the output is "local".

After calling my_func(), print(x) is executed outside the function. Since this is the global scope, Python refers to the global variable, and its value remains "global".

The global Keyword

The global keyword allows you to modify a variable defined in the global scope from within a function. Without the global keyword, any assignment to a variable inside the function would create a new local variable, leaving the global variable unchanged.

For example:

x = "global" # Global variable

def my_func():
    global x # Refers to the global variable x
    x = "local" # Modifies the global varaible 
    print(x)  # Prints the modified global variable

my_func() # Calls the function my_func
print(x)   # Prints the modified global variable

In this example, a global variable x is defined with the value "global".

Inside my_func(), the statement global x allows the function to access and modify the global variable instead of creating a local one. The assignment x="local" changes the value of global variable.

When print(x) is executed inside the function, it prints "local" and printing x outside the function also prints "local", confirming that the global variable was modified by the function.

Built-in Scope

The built-in scope contains Python’s predefined names, such as built-in functions, data types, and constants, which are available throughout the program without requiring any imports.

For example:

x = 15              # int -> built-in data type
print(len("hello")) # print() and len() -> built-in functions
print(True)         # True -> built-in variable (constant)