A closure is a nested function that remembers variables from its enclosing scope even after that outer function has returned.
Those remembered names live in the inner function's __closure__ cells. Closures power decorators, callbacks, and lightweight function factories.
def make_multiplier(factor):
def multiply(x):
return x * factor # "factor" is a free variable
return multiply
double = make_multiplier(2)
triple = make_multiplier(3)
print(double(10)) # 20
print(triple(10)) # 30
# Late-binding pitfall with loops
funcs = []
for i in range(3):
funcs.append(lambda: i) # all see final i
print([f() for f in funcs]) # [2, 2, 2]
funcs = []
for i in range(3):
funcs.append(lambda i=i: i) # bind current i as default
print([f() for f in funcs]) # [0, 1, 2]
# Mutating enclosed state with nonlocal
def counter():
n = 0
def inc():
nonlocal n
n += 1
return n
return inc
c = counter()
print(c(), c()) # 1 2Interview tip: Define closure as "function + captured enclosing state," then mention nonlocal and the late-binding loop gotcha.