Intermediate·18 min·0/47 done

Python Scope

Where names live, how mutable arguments behave, and how closures capture variables.

Why it matters: Shared lists and late-bound closures cause bugs that only show up on the second call.

Basics

LEGB Rule

Python looks up names in this order:

  1. Local
  2. Enclosing (outer function)
  3. Global (module)
  4. Built-in (len, print, ...)

Reading a global is fine. Assigning creates a new local unless you use global. Common mistake: naming a variable list or sum and shadowing the built-in.

Tiny example

Read a global name from inside a function.

model = "mini"
def show():
    print(model)

show()

Basics

Mutable Arguments

Python passes object references.

Immutable values (int, str, tuple) cannot be changed by the callee.

Mutable values (list, dict, set) can. items.append(x) changes the caller's list. items = items + [x] does not.

Copy first with list(items) when you do not want shared changes.

Tiny example

Appending inside a function changes the caller's list.

batch = ["a"]
def add(items):
    items.append("b")

add(batch)
print(batch)

Basics

Closures

A closure is a nested function that keeps variables from the outer scope.

Closures capture the variable, not a snapshot of its value.

In loops, bind the value with a default: lambda s, t=t: s >= t.

Tiny example

A factory returns a filter closed over a threshold.

def make_keep(threshold):
    def keep(score):
        return score >= threshold
    return keep

print(make_keep(0.7)(0.8))

Then AI / ML

AI / ML examples

Same idea, used in real AI work. Press Try in lab to run it.

AI / ML example

AI / ML: mutate vs rebind

append changes the caller. Rebinding does not.

In AI / ML: Message histories and batch collectors must not mutate by accident.

example.py

Python

def mutates(items):
    items.append("x")

def rebinds(items):
    items = items + ["x"]
    return items

a = ["start"]
mutates(a)
print("mutated:", a)

b = ["start"]
rebinds(b)
print("rebound caller:", b)

AI / ML example 2

AI / ML: late-binding trap

Bind each threshold at creation time.

In AI / ML: Score filters built in a loop must bind each threshold.

example.py

Python

broken = [lambda s: s >= t for t in (0.5, 0.7, 0.9)]
fixed = [lambda s, t=t: s >= t for t in (0.5, 0.7, 0.9)]
print([f(0.8) for f in broken])
print([f(0.8) for f in fixed])

Takeaways

  • 1Names resolve Local, Enclosing, Global, Built-in.
  • 2Mutable arguments can change the caller's data.
  • 3Closures capture variables; bind loop values with defaults.
Certificate