Skip to content
  • Scope & Closures · Python

Scope & Closures

LearnViaNotes @learnvianotes· 1 min read

Python resolves names with the LEGB rule, and inner functions can close over variables from the function that created them.

LEGB: where a name is looked up

  1. Local

    Names assigned inside the current function.

  2. Enclosing

    Locals of any enclosing (outer) functions.

  3. Global

    Names at the top level of the module.

  4. Built-in

    len, print, range, … from the builtins module.

Python
x = "global"

def outer():
    x = "enclosing"
    def inner():
        return x              # found in the enclosing scope
    return inner()

print(outer(), x)             # enclosing global

global and nonlocal

Assigning to a name makes it local to that function. To rebind an outer name, declare it first.

Python
count = 0

def bump():
    global count
    count += 1

def make_counter():
    n = 0
    def inc():
        nonlocal n            # rebinding the enclosing variable
        n += 1
        return n
    return inc

bump(); bump()
c = make_counter()
c(); c()
print(count, c())             # 2 3

Closures

Python
def multiplier(k):
    def times(x):
        return x * k          # k is captured
    return times

double, triple = multiplier(2), multiplier(3)
print(double(5), triple(5))                       # 10 15
print(double.__closure__[0].cell_contents)        # 2

Late binding in loops

Python
# Every lambda sees the final value of i:
fns = [lambda: i for i in range(3)]
print([f() for f in fns])          # [2, 2, 2]

# A default argument captures each value at definition time:
fns = [lambda i=i: i for i in range(3)]
print([f() for f in fns])          # [0, 1, 2]

Free for students and teachers

Write notes like this one

Cards for every idea, quizzes and flashcards, read aloud — on the web and your phone.

Something wrong with this note? Open it to report