Skip to content

locals() Function

The locals() function returns a dictionary containing the current local symbol table.

Complexity Reference

Operation Time Space Notes
locals() O(n) O(n) Creates snapshot; n = local variables
Access variable O(1) avg O(1) Dict key lookup; O(n) worst case with collisions

Basic Usage

Get Local Variables - Time: O(n)

def example():
    x = 10
    y = 20
    z = x + y

    # Get all local variables - O(n)
    local_vars = locals()

    print(local_vars)
    # Output: {'x': 10, 'y': 20, 'z': 30}

    print(local_vars['x'])  # 10
    print(local_vars['y'])  # 20

example()

Function Scope

def outer():
    x = "outer"

    def inner():
        y = "inner"

        # locals() returns inner's variables - O(n)
        print(locals())  # {'y': 'inner'}

        # Note: x is not in locals(), it's in enclosing scope
        print(x)  # Can still access outer's x

    inner()

    # locals() returns outer's variables - O(n)
    print(locals())  # {'x': 'outer', 'inner': <function>}

outer()

Module Level

# At module level, locals() == globals()
x = 10
y = 20

# Get module-level locals - O(n)
local_vars = locals()
print('x' in local_vars)  # True
print('y' in local_vars)  # True

Comparing locals() and globals()

Scope Differences - Time: O(n)

global_var = "global"

def example():
    local_var = "local"

    # locals() - current function scope - O(n)
    local_dict = locals()
    print(local_dict)
    # {'local_var': 'local'}

    # globals() - global scope - O(n)
    global_dict = globals()
    print('global_var' in global_dict)  # True
    print('local_var' in global_dict)   # False

example()

Inspecting Variables

def analyze():
    a = 1
    b = 2
    c = 3

    # Get local variables - O(n)
    local_vars = locals()

    # Iterate through locals - O(n)
    for name, value in local_vars.items():
        print(f"{name} = {value}")
    # Output:
    # a = 1
    # b = 2
    # c = 3

analyze()

Practical Examples

Dynamic Variable Access

def get_var(var_name):
    """Get local variable by name."""
    x = 10
    y = 20
    z = 30

    # Get locals and access by name - O(n) to get, O(1) to access
    local_dict = locals()

    if var_name in local_dict:
        return local_dict[var_name]
    else:
        return None

print(get_var('x'))  # 10
print(get_var('unknown'))  # None

Debugging/Inspection

def debug_function(a, b, c):
    result = a + b + c
    multiplied = result * 2

    # Inspect all local variables - O(n)
    locals_dict = locals()

    print("=== Local Variables ===")
    for name, value in sorted(locals_dict.items()):
        print(f"  {name}: {value} ({type(value).__name__})")

    return multiplied

debug_function(1, 2, 3)
# Output:
# === Local Variables ===
#   a: 1 (int)
#   b: 2 (int)
#   c: 3 (int)
#   locals_dict: {...}
#   multiplied: 12 (int)
#   result: 6 (int)

Variable Existence Check

def check_variable(var_name):
    """Check if variable exists in current scope."""
    x = "exists"

    # Check using locals() - O(n) to get, O(1) for membership
    if var_name in locals():
        print(f"{var_name} exists with value: {locals()[var_name]}")
    else:
        print(f"{var_name} does not exist")

check_variable('x')  # x exists with value: exists
check_variable('y')  # y does not exist

Comparison with globals()

global_x = "global"

def func():
    local_x = "local"

    # locals() in function - O(n)
    local_dict = locals()

    # globals() in function - O(n)
    global_dict = globals()

    # Get specific values - O(1) each
    local_val = local_dict.get('local_x')    # "local"
    global_val = global_dict.get('global_x') # "global"

    return local_val, global_val

print(func())  # ('local', 'global')

# At module level, locals() == globals()
print(locals() == globals())  # True

Important Notes

Modifications

def modify_attempt():
    x = 10

    # Get locals - O(n)
    local_dict = locals()

    # Modify the dictionary - O(1)
    local_dict['x'] = 20

    # Note: modifying locals() dict does NOT change x!
    print(x)  # Still 10, not 20

    # This is different in class body where locals() modifications ARE applied

modify_attempt()

Class Definition

# In class definition, locals() dict modifications ARE applied
class MyClass:
    x = 10
    local_dict = locals()  # Get locals - O(n)
    local_dict['y'] = 20   # Modify dictionary - O(1)

    print(x)  # 10
    print(y)  # 20 - THIS WORKS because we're defining the class
    # So y becomes a class attribute

print(MyClass.x)  # 10
print(MyClass.y)  # 20

Performance Considerations

def heavy_function(a, b, c, d, e, f, g, h):
    """Function with many local variables."""

    # Getting locals() is O(n) where n = number of locals
    # For 8 parameters, this is minimal overhead
    local_dict = locals()

    # Access is O(1)
    return local_dict.get('a', 0)

# Don't use locals() in tight loops for performance
# It creates a copy of the local symbol table each time

# ✅ Better for performance:
def fast_access(a, b, c):
    return a + b + c  # Direct access, no locals() call

# ❌ Slower:
def slow_access(a, b, c):
    return locals()['a'] + locals()['b'] + locals()['c']  # Creates dict 3 times!

Best Practices

# ✅ DO: Use locals() for debugging/introspection
def debug():
    x = 1
    y = 2
    print(locals())  # Good for understanding scope

# ✅ DO: Use it for variable existence checks
if 'var_name' in locals():
    process(locals()['var_name'])

# ✅ DO: Understand it's a snapshot
local_dict = locals()
x = 10
print('x' in local_dict)  # False - dict is a snapshot

# ❌ DON'T: Rely on modifications to locals()
locals()['x'] = 20
print(x)  # Still old value (except in class body)

# ❌ DON'T: Use in tight loops for performance
for i in range(1000000):
    v = locals()['var']  # Inefficient - creates dict each time

# ❌ DON'T: Serialize/pickle locals() dict
# It contains references that may not be picklable