LambdaLabTM
Computer Science · Class 12 · Functions
FunctionsScope⏱️ 15 min read

Scope of a Variable

The scope of a variable is the part of the program where its name means something. A name made inside a function lives only there and disappears when the function ends; a name made outside every function is visible throughout. Getting this right is what stops two functions quietly overwriting each other's work.

1Local scope: made inside, gone outside

local_scope.py
def show():
    message = 'I live inside show()'
    print(message)

show()
print(message)
Output
I live inside show()
Traceback (most recent call last):
  File "local_scope.py", line 6, in <module>
    print(message)
          ^^^^^^^
NameError: name 'message' is not defined

The function printed it happily. One line later the same name does not exist. message is a local variable — it was created when the function ran, and destroyed when it finished.

Key Takeaway
Local names are a feature, not a limitation. It is what lets you write twenty functions that all use a counter called i without any of them interfering with the others. Each call gets its own private set of names.
same_name_different_functions.py
def one():
    x = 'in one'
    print(x)

def two():
    x = 'in two'
    print(x)

one()
two()
Output
in one
in two

Two variables, both called x, with no relationship to each other whatsoever. And a parameter is local too — it is just a local name that the call fills in for you:

params_are_local.py
def f(n):
    n = n * 2
    return n

value = 7
print(f(value))
print(value)
Output
14
7

2Global scope: made outside, visible inside

A name created outside every function is global, and a function can read it without being given it:

global_read.py
school = 'LambdaLab Public School'

def header():
    print(school)            # reading a global — allowed

header()
Output
LambdaLab Public School

Python looks for school among the function's own local names first, does not find it, and looks outside. That is the whole rule: local first, then global.

3Assigning inside makes a new local

Here is the behaviour that surprises everyone, and it is worth staring at until it stops being surprising:

shadow.py
count = 10

def change():
    count = 99               # this makes a NEW local variable
    print('inside :', count)

change()
print('outside:', count)
Output
inside : 99
outside: 10
Watch Out
Assigning to a name inside a function creates a local of that name, even if a global with the same name exists. The function did not change the global count — it made its own, used it, and threw it away. The global was never touched, which is why it is still 10.

Python decides this when it compiles the function, not while it runs — so a name assigned anywhere in the body is local everywhere in the body, including on lines above the assignment:

unbound_local.py
total = 5

def broken():
    print(total)             # Python already knows total is local here
    total = 6                # …because of this line

broken()
Output
Traceback (most recent call last):
  File "unbound_local.py", line 7, in <module>
    broken()
  File "unbound_local.py", line 4, in broken
    print(total)             # Python already knows total is local here
          ^^^^^
UnboundLocalError: cannot access local variable 'total' where it is not associated with a value

“Local variable, not associated with a value” is Python telling you exactly that: it decided total was local because of the assignment below, and then you asked to read it before anything had been put in it.

4global: changing the outside one on purpose

When you really do mean the global, say so:

global_keyword.py
count = 10

def change():
    global count             # 'count' means the outside one
    count = 99
    print('inside :', count)

change()
print('outside:', count)
Output
inside : 99
outside: 99

One word, and now both lines print 99. global count tells Python not to make a local — every mention of count in this function refers to the one outside.

Tip
Use it rarely. A function that changes globals is a function you cannot understand on its own: to know what it does, you must know what else in the program touches the same names. Passing a value in as a parameter and handing the answer back with return keeps the function self-contained, which is the whole point of writing functions.
Changing a global
total = 0 def add(n): global total total = total + n add(5) add(3) print(total)

Works, and the function is now tangled up with the rest of the program.

Parameter in, value out
def add(total, n): return total + n total = 0 total = add(total, 5) total = add(total, 3) print(total)

Same answer, and add can be read, tested and reused on its own.

5The rules, all together

Inside a functionWhat happens
Reading a name that is localUses the local one.
Reading a name that is only globalUses the global one. No keyword needed.
Assigning to a nameCreates a local — even if a global of that name exists.
Assigning after declaring it globalChanges the global itself.
Reading a name that is assigned later in the bodyUnboundLocalError — it is local, and still empty.
Changing a list that was passed inThe caller sees the change. The name is local; the list is not.
scope.py

6Recap

Local: made inside, gone outside

Created when the function runs, destroyed when it ends. Parameters are local too.

Global: made outside, readable inside

A function looks for a local name first, then a global one. Reading needs no keyword.

Assigning inside makes a local

count = 99 inside did not touch the count outside. That is the commonest surprise in this chapter.

global says you mean the outer one

Use it rarely: a function that changes globals cannot be understood on its own.

✍️ Now write these yourself
  1. 1

    Make a variable inside a function and try to print it after the call.

    Hint · NameError. The name existed only while the function was running.

  2. 2

    Write the count = 10 / count = 99 example both with and without global.

    Hint · Without: 99 inside, 10 outside. With: 99 in both places. One keyword is the whole difference.

  3. 3

    Read a global at the top of a function and assign to it at the bottom.

    Hint · UnboundLocalError. Python decided the name was local before it ran a single line.

  4. 4

    Rewrite a function that uses global so it takes a parameter and returns a value instead.

    Hint · total = add(total, 5). The function stops depending on anything outside itself.

Quick Check

count = 10 outside; a function assigns count = 99 and prints it. What do the two prints show?

Quick Check

Why does reading a global at the top of a function fail if you assign to it lower down?

Quick Check

When do you actually need the global keyword?