Scope and Variables
Concepts covered: Scope
Scope determines where a variable exists and can be accessed. Understanding scope prevents bugs where variables unexpectedly have wrong values or do not exist when you expect them to. Python has 2 main scopes relevant to functions: local scope (inside a function) and global scope (outside all functions).
Scope definition
- Local scope - variables created inside a function, only visible there
- Global scope - variables created outside all functions, visible everywhere
- A variable's scope is determined by where it is created
Local variables
Variables created inside a function are local to that function. They're created when the function starts running and destroyed when the function finishes. They don't exist outside the function and can't be accessed from elsewhere:
def calculate():
result = 100
multiplier = 5
total = result * multiplier
print("Inside function:", total)
calculate()
# print(result) # NameError! result does not exist here
# print(multiplier) # NameError! multiplier does not exist here
# print(total) # NameError! total does not exist hereThe isolation is deliberate. You can use the same variable name in different functions without conflict, because each function has its own local scope.
def function_one():
# x is local to function_one
x = 10
print("function_one x:", x)
def function_two():
# x is local to function_two, completely separate
x = 99
print("function_two x:", x)
function_one()
function_two()
function_one()Output:
function_one x: 10 function_two x: 99 function_one x: 10
Global variables
Variables created outside any function are global. They exist for the entire program and can be read from inside functions. But you can't modify them from inside a function without special syntax (which we'll cover in the intermediate lesson).
TAX_RATE = 0.08
COMPANY_NAME = "ACME Corp"
def calculate_tax(price):
# Can READ global variables
tax = price * TAX_RATE
return tax
def print_receipt(item, price):
# Can READ globals too
tax = calculate_tax(price)
total = price + tax
print(COMPANY_NAME)
print("-" * 20)
print(item + ": $" + str(price))
print("Tax: $" + str(tax))
print("Total: $" + str(total))
print_receipt("Widget", 100)Output:
ACME Corp -------------------- Widget: $100 Tax: $8.0 Total: $108.0
Global variables named in ALL_CAPS indicate constants that should not change. Functions can read these values freely, so they are an easy way to share configuration across your program.
Parameters as local variables
Parameters are local variables too. When you call a function, Python creates local variables from the parameters and assigns the argument values to them. Modifying a parameter inside the function doesn't affect variables outside:
def attempt_to_modify(x):
print("Inside function, before:", x)
# Modifies the local x only
x = x * 2
print("Inside function, after:", x)
number = 5
print("Before function call:", number)
attempt_to_modify(number)
# Unchanged!
print("After function call:", number)Output:
Before function call: 5 Inside function, before: 5 Inside function, after: 10 After function call: 5
The parameter x inside the function is a separate variable that happens to start with the same value as number. Changing x does not change number. This is called pass by value for simple types like numbers and strings.
Scope lookup order
When you use a variable name, Python searches for it in order: first local scope, then enclosing scopes (for nested functions), then global scope, then built-in scope. It uses the first match it finds:
x = "global"
def outer():
x = "outer"
def inner():
x = "inner"
print("inner sees:", x)
inner()
print("outer sees:", x)
outer()
print("global sees:", x)Output:
inner sees: inner outer sees: outer global sees: global
Each scope has its own x. The inner function finds its local x first and uses it, the outer function finds its own local x, and the global code finds the global x, so the 3 never interfere.
Local variables created inside a function are destroyed when the function returns, which keeps each call isolated.
Global variables are best used for true constants that don't change during the program, like configuration settings. Passing values through parameters and returning results through return values produces more predictable, testable functions.
Because Python checks local scope before global scope, a local variable with the same name as a global always shadows the global inside that function.
About this lesson
This section is part of the Functional Programming: Beginner lesson on DataDriven, the home of data engineering. Lessons cover SQL, Python, Spark, data modeling and pipeline architecture, and each section pairs its explanation with worked examples and practice you run as you go.