locals()
locals() Returns:
dict · Added in v3.0 · Updated March 13, 2026 · Built-in Functions built-in namespace local dictionary introspection
The locals() function returns a dictionary containing the current local namespace. This dictionary holds all local variables, parameters, and other symbols defined within the current scope. Unlike globals(), which returns module-level variables, locals() captures variables in the immediate enclosing scope — typically the current function or module level.
Syntax
locals()
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| (none) | — | — | This function takes no arguments. |
Returns: A dict representing the current local symbol table. At module level, this is the same as globals().
Examples
Viewing local variables in a function
def calculate_stats(numbers):
"""Calculate and display statistics."""
total = sum(numbers)
count = len(numbers)
average = total / count
# Inspect local variables
local_vars = locals()
print(f"Local variables: {local_vars}")
# {'numbers': [1, 2, 3, 4, 5], 'total': 15, 'count': 5, 'average': 3.0}
return average
result = calculate_stats([1, 2, 3, 4, 5])
# Local variables: {'numbers': [1, 2, 3, 4, 5], 'total': 15, 'count': 5, 'average': 3.0}
Accessing local variables dynamically
def process_data(name, value):
"""Process data using local variables."""
result = f"{name}: {value}"
status = "completed"
# Access local variable by name
print(locals()['name'])
# process_data
# Modify via locals() - only works inside function, not at module level
return result
output = process_data("test", 42)
# test
Capturing locals for later use
def create_snapshot():
"""Capture current local state."""
x = 10
y = 20
z = "hello"
# Return copy of local namespace
return locals().copy()
snapshot = create_snapshot()
print(snapshot)
# {'x': 10, 'y': 20, 'z': 'hello'}
# Original locals still exist
print(x) # NameError: name 'x' is not defined
Using with debugging
def inspect_locals():
"""Debug helper to inspect all local variables."""
for name, value in locals().items():
print(f" {name} = {value!r}")
print(f"Total locals: {len(locals())}")
def example_function(a, b):
x = a * 2
y = b + 10
message = "Calculation complete"
print("Local variables:")
inspect_locals()
return x + y
example_function(5, 3)
# Local variables:
# a = 5
# b = 3
# x = 10
# y = 13
# message = 'Calculation complete'
# Total locals: 5
Comparing locals() and globals()
module_var = "I'm global"
def compare_scopes():
local_var = "I'm local"
print("--- locals() ---")
local_dict = locals()
print(f"'local_var' in locals: {'local_var' in local_dict}")
print(f"'module_var' in locals: {'module_var' in local_dict}")
print("\n--- globals() ---")
global_dict = globals()
print(f"'local_var' in globals: {'local_var' in global_dict}")
print(f"'module_var' in globals: {'module_var' in global_dict}")
compare_scopes()
# --- locals() ---
# 'local_var' in locals: True
# 'module_var' in locals: True (at module level scope, both merge)
#
# --- globals() ---
# 'local_var' in globals: False
# 'module_var' in globals: True
Common Patterns
Conditional variable inspection
def complex_function(data, debug=False):
"""Example of conditional debugging with locals."""
processed = []
for item in data:
transformed = item * 2
processed.append(transformed)
if debug:
print("Debug: locals() at end of loop")
for k, v in locals().items():
if not k.startswith('_'):
print(f" {k}: {v}")
return processed
result = complex_function([1, 2, 3], debug=True)
# Debug: locals() at end of loop
# data: [1, 2, 3]
# processed: [2, 4, 6]
# item: 3
# transformed: 6
Snapshot testing
def capture_state():
"""Capture state for testing purposes."""
user_name = "Alice"
session_id = "abc123"
permissions = ["read", "write"]
return {
'state': locals().copy(),
'timestamp': '2026-03-06'
}
state = capture_state()
print(state)
# {'state': {'user_name': 'Alice', 'session_id': 'abc123', 'permissions': ['read', 'write']}, 'timestamp': '2026-03-06'}
Default values from locals
def process_with_defaults(required_param, optional_param=None):
"""Use locals() to build parameter dict."""
# Extract all parameters as a dictionary
params = {k: v for k, v in locals().items() if k != 'optional_param' or v is not None}
print(params)
return params
process_with_defaults("test")
# {'required_param': 'test'}
process_with_defaults("test", "optional")
# {'required_param': 'test', 'optional_param': 'optional'}
Important Behaviors
At module level, locals() == globals()
# At the module (top-level) scope, locals() returns the same dictionary as globals()
print(locals() is globals()) # True at module level
Returns live snapshot
# locals() returns a snapshot that may not reflect later modifications
def example():
x = 1
snapshot = locals()
x = 2
print(snapshot['x']) # Still shows 1, not updated!
# To get updated values, call locals() again
print(locals()['x']) # Shows 2
Does not include nonlocal variables
def outer():
outer_var = "outer"
def inner():
# locals() in inner does NOT include outer_var
# That requires using nonlocal or closure inspection
inner_var = "inner"
print(f"Inner locals: {locals()}")
# {'inner_var': 'inner'}
inner()
outer()
Errors
No parameters
# locals() does not accept any arguments
locals('invalid')
# TypeError: locals() takes no arguments (0 positional arguments)
Modifications are unreliable
# Modifying the returned dict does NOT modify actual local variables
def test():
x = 10
locals()['x'] = 20
print(x) # Still prints 10 - modification has no effect!
See Also
- built-in::globals — returns a dictionary of the global namespace
- built-in::vars — returns
__dict__of an object or local namespace - built-in::dir — returns list of valid attributes