Chapters
Python114 chapters

FunctionsChapter 53 of 114

Scope

Where a name is visible, and the order Python searches.

Local names

A name assigned inside a function belongs to that function and disappears when it returns:

Python
def work():
    total = 10
    print("inside:", total)

work()

try:
    print(total)
except NameError as problem:
    print("NameError:", problem)

Output

inside: 10
NameError: name 'total' is not defined

The search order

When Python meets a name it looks in four places, in order:

  1. Local — this function
  2. Enclosing — any function wrapped around it
  3. Global — the module
  4. Built-inprint, len and friends
Python
name = "global"

def outer():
    name = "enclosing"

    def inner():
        print(name)

    inner()

outer()
print(name)

Output

enclosing
global

inner has no name of its own, so it found the enclosing one before the global.

Assignment makes a name local

The decision is made for the whole function, before it runs, so a name assigned anywhere in the body is local everywhere in it:

Python
count = 10

def show():
    print(count)

show()

Output

10

Add an assignment and the same read breaks:

Python
count = 10

def bump():
    try:
        print(count)
        count = count + 1
    except UnboundLocalError as problem:
        print("UnboundLocalError:", problem)

bump()

Output

UnboundLocalError: cannot access local variable 'count' where it is not associated with a value

Nothing about the print line changed. The assignment below it made count local for the whole function.

global and nonlocal

global rebinds a module-level name:

Python
count = 0

def bump():
    global count
    count += 1

bump()
print(count)

Output

1

nonlocal rebinds a name in the enclosing function, which is what you need for a counter that lives in a closure:

Python
def make_counter():
    count = 0

    def increment():
        nonlocal count
        count += 1
        return count

    return increment

counter = make_counter()
print(counter(), counter(), counter())

Output

1 2 3

Without nonlocal, count += 1 would try to make a local and raise UnboundLocalError.

Neither is needed to mutate

Both keywords are about rebinding a name. Changing an object in place needs no declaration:

Python
scores = []

def record(value):
    scores.append(value)

record(1)
print(scores)

Output

[1]

Blocks are not scopes

Unlike many languages, if, for and while do not create a scope. A name assigned inside one survives:

Python
for i in range(3):
    last = i

print(i, last)

Output

2 2

Only functions, classes, modules and comprehensions do.

Shadowing builtins

A local name can hide a builtin for the rest of that scope:

Python
def total(numbers):
    sum = 0
    for n in numbers:
        sum += n
    return sum

print(total([1, 2, 3]))

Output

6

That works, and inside total the real sum is gone. Name it running_total and the problem never arises.

Test yourself

3 questions

In what order does Python look up a name?

Show the answer

Local, enclosing, global, built-in — The first three letters spell LEGB, which is how most people remember it.

Why can reading a global fail with UnboundLocalError?

Show the answer

An assignment anywhere in the function makes the name local for the whole function — The decision is made before the function runs, so a later assignment affects an earlier read.

Which keyword rebinds a name in an enclosing function?

Show the answer

nonlocal — global reaches the module level; nonlocal reaches the function one level out, which is what closures need.

Next chapter

Recursion

A function that calls itself, and the base case that stops it.