Learning LibraryCore Coding LibraryTeens

Scope in Python: where a variable lives

You set total inside a function, and the total outside doesn't budge. That isn't a bug in Python. It's scope, and it's what stops functions from trampling each other's data.

The big idea

A variable assigned inside a function is local: it exists only while that call runs and is invisible outside it.

See it in code

1The basics

profit is created inside the function and disappears when the call ends. The only thing that survives is what you return:

python
def profit_per_tee(price, cost):
    profit = price - cost
    return profit

answer = profit_per_tee(38, 14)
print("Returned:", answer)
Run it. A local variable's short life:
Returned: 24

Outside the function there is no profit; asking for it would raise a NameError. The value escaped only because it was returned and bound to answer.

2A step further

Scope works one way. A function can read a variable defined outside it, which is handy for settings shared across the program:

python
clearance = 10

def leftover_value(unsold):
    return unsold * clearance

print("Value of 120 unsold tees: $", leftover_value(120))
Run it. Reading an outer variable:
Value of 120 unsold tees: $ 1200

clearance isn't a parameter or a local, so Python looked outward and found it at the top level. Reading outward is allowed.

3At Evergreen

Assigning is different. An assignment inside a function creates a new local with that name, and leaves the outer one untouched:

python
total_sold = 0

def record_sale(quantity):
    total_sold = quantity
    print("inside the function:", total_sold)

record_sale(12)
print("outside the function:", total_sold)

def new_total(current, quantity):
    return current + quantity

total_sold = new_total(total_sold, 12)
print("after returning the result:", total_sold)
Run it. Two variables that share a name:
inside the function: 12
outside the function: 0
after returning the result: 12

The first function changed its own private total_sold, then threw it away. The second takes the current value in, returns a new one, and lets the caller decide where it goes.

The same idea, everywhere

Local scope is why you can use i, total, or result in fifty functions without any of them colliding. It's also why well-written functions are easy to test: everything they need comes in through parameters.

Try it yourself

Rename the inner variable in record_sale to sale_amount. The behavior doesn't change at all, which proves the two names were never connected. Then make record_sale return a value instead of printing.

The common mistake

Reaching for global to make the first version work. It does work, but now any function can change total_sold and you can't tell which one did. Pass values in, and return results out.

What it unlocks

Scope is the reason return values matter. When several functions genuinely need to share changing data, bundle it into an object with classes.