Contact
Evil Genius SocietyHomeLearnForumLeaderboardSocialsMessages
← Back to module

Lesson 5 of 10

Scope is the region of code where a variable exists. Variables created inside a function are local to it — they are born when the function runs and vanish when it returns.

def calculate():
    result = 42
    print(result)

calculate()
print(result)

That last line raises NameError: name 'result' is not defined. result only ever existed inside calculate.

This is a feature, not a limitation. It means two functions can both use a variable called total without interfering with each other — you never have to worry about what names another function chose.

Global scope

Variables defined outside any function are global and can be read anywhere:

tax_rate = 0.1

def total(price):
    return price + (price * tax_rate)

print(total(100))

Reading versus assigning

Here is the part that surprises people. Reading a global works fine. Assigning to that name inside a function creates a new local variable instead:

count = 0

def increment():
    count = count + 1

increment()

That raises UnboundLocalError. Because count is assigned somewhere in the function, Python treats it as local throughout the function — so count + 1 tries to read a local that has no value yet.

The global keyword

global tells Python you really do mean the outer variable:

count = 0

def increment():
    global count
    count = count + 1

increment()
increment()
print(count)

This works, but use it sparingly. A function that quietly modifies global state is hard to test and hard to reason about — you can't tell what it does by looking at its inputs and output.

Almost always, the better shape is to take a value in and return a new one:

def increment(count):
    return count + 1

count = 0
count = increment(count)
count = increment(count)
print(count)

Same result, no hidden dependency. The function is now completely predictable.

Parameters are local too

Reassigning a parameter inside a function does not affect the caller's variable:

def change(value):
    value = 99
    return value

original = 1
print(change(original))
print(original)

Careful though — this holds for immutable values like numbers and strings. If you pass a list and mutate it with .append(), the caller does see the change, because both names point at the same list.

def add_item(items):
    items.append("new")

basket = ["apple"]
add_item(basket)
print(basket)

Try it yourself

Show that a local variable doesn't leak, and that a global can be read.

Checkpoint

  • Variables made inside a function are local and disappear when it returns.
  • Globals can be read inside functions but not reassigned without global.
  • Prefer parameters and return values over global.
  • Mutating a list argument is visible to the caller; reassigning a parameter is not.

Questions about this lesson

Log in to ask a question.