Global vs Local Scope in Python

Data Science Tool Box Mar 18, 2026

Global vs Local Scope in Python

Understanding variable scope is crucial for writing clean, bug-free data science code. In 2026, following proper scoping rules helps prevent subtle bugs, improves code maintainability, and makes your functions more predictable and reusable.

TL;DR — Core Rules

  • Local scope: Variables defined inside a function
  • Global scope: Variables defined outside any function
  • Functions can read global variables but cannot modify them without global keyword
  • Avoid modifying global variables from inside functions

1. Basic Scope Example

total_sales = 0          # Global variable

def process_transaction(amount: float) -> float:
    tax_rate = 0.08      # Local variable
    total = amount * (1 + tax_rate)
    
    # This would cause UnboundLocalError if we tried to modify global without 'global'
    # total_sales += total   # ❌ Wrong
    
    return total


def update_total_sales(amount: float) -> None:
    global total_sales     # Explicitly declare we want to modify global
    total_sales += amount

2. Common Data Science Scope Patterns (and Pitfalls)

def run_experiment(data):
    model_name = "RandomForest"        # Local variable
    
    # Bad practice - modifying global inside function
    # global results
    # results.append(...)  
    
    # Better approach - return values instead
    metrics = calculate_metrics(data, model_name)
    return metrics


import pandas as pd


# Recommended pattern: Pass data explicitly, return results
def calculate_metrics(df: pd.DataFrame, model_name: str) -> dict:
    """Pure function - no side effects"""
    # All variables here are local
    accuracy = 0.92
    f1_score = 0.89
    
    return {
        "model": model_name,
        "accuracy": accuracy,
        "f1_score": f1_score
    }

3. Best Practices for Data Science in 2026

  • Avoid global variables in functions whenever possible
  • Pass all required data as parameters instead of relying on globals
  • Use pure functions that return values instead of modifying global state
  • Only use the global keyword in very specific cases (like configuration or counters)
  • Keep functions self-contained and predictable
  • Use dependency injection or configuration objects instead of global variables

How Python Finds a Name

Python looks up names using the LEGB rule: Local, Enclosing, Global, then Built-in. A variable assigned inside a function is local to it unless declared otherwise, so it disappears when the function returns.

Reading a global inside a function works, but assigning to it creates a new local name. The global keyword changes that, yet passing values as parameters and returning results is almost always clearer and easier to test.

Worked Example: Local, Global and Shadowing

The code shows a local variable, an UnboundLocalError, and the cleaner parameter approach.

threshold = 100

def count_large(values):
    big = [v for v in values if v > threshold]
    return len(big)

print(count_large([50, 150, 200]))

def broken():
    try:
        threshold += 1
    except UnboundLocalError as err:
        print("UnboundLocalError:", err)

broken()

def count_large_param(values, limit):
    return sum(v > limit for v in values)

print(count_large_param([50, 150, 200], limit=120))

Reading threshold works, but assigning to it inside broken makes Python treat it as local, so it fails before a value exists. Passing limit as a parameter removes the dependency on global state.

Practical Tips

Notebooks make scope problems more likely, because variables from earlier cells remain in the global namespace. A function that accidentally reads such a variable may work in the notebook and fail as soon as it is moved into a script. Restarting the kernel and running all cells from the top is a quick way to catch these hidden dependencies before sharing your work.

Constants are the reasonable exception: module-level values written in capital letters, such as TAX_RATE, are read but never reassigned, so they do not cause the same problems as changing globals.

Common Mistakes

  • Changing globals from inside functions.
  • Shadowing built-ins such as sum or max with local names.
  • Assuming local variables survive after the call.
  • Relying on notebook globals that are not defined in scripts.

Quick Summary

  • Python resolves names with LEGB.
  • Assignment makes a name local.
  • global works but hurts testability.
  • Prefer parameters and return values.

Conclusion

Scope is one of the most important concepts in Python programming. In data science, following the principle of "explicit is better than implicit" means avoiding global variables in functions and preferring to pass data as parameters and return results explicitly. This approach leads to cleaner, more testable, and more maintainable code.

Next steps:

  • Review your current data science scripts and replace any global variable modifications inside functions with proper parameter passing and return values

Related Tutorials

Share:
Last updated: March 2026
Built-in Functions in Python 2026 str() in Python 2026: String Conversion + Modern Formatting & Best Practices memoryview with JAX in Python 2026: Zero-Copy NumPy → JAX Array Interop + Efficient ML Examples memoryview with TensorFlow in Python 2026: Zero-Copy NumPy → Tensor Interop + GPU Pinning & ML Examples memoryview with TensorFlow in Python 2026: Zero-Copy NumPy → Tensor Interop + ML Examples memoryview with NumPy & PyTorch in Python 2026: Zero-Copy Views, Efficient Slicing & ML Interop Examples memoryview with NumPy in Python 2026: Zero-Copy Views, Efficient Slicing & Real ML Examples memoryview() in Python 2026: Zero-Copy Magic for Large Binary Data + Real Examples import() in Python 2026: How It Works, Security Risks & Modern Alternatives (importlib) zip() in Python 2026: How to Use It, strict=True Behavior & Real-World Examples vars() in Python 2026: Accessing Object Namespace + Modern Introspection Patterns type() in Python 2026: Dynamic Type Inspection & Object Creation + Modern Patterns tuple() in Python 2026: Immutable Sequences + Modern Patterns & Best Practices super() in Python 2026: Method Resolution & Modern Inheritance Patterns sum() in Python 2026: Summing Iterables + Modern Numeric Patterns & Best Practices staticmethod() in Python 2026: Static Methods, Utility Functions & Modern Best Practices sorted() in Python 2026: Sorting Iterables + Modern Patterns & Best Practices slice() in Python 2026: Creating Slice Objects + Modern Patterns & Best Practices setattr() in Python 2026: Dynamic Attribute Setting + Modern Patterns & Safety set() in Python 2026: Mutable Sets Creation + Modern Patterns & Best Practices