Skip to content

Latest commit

 

History

History
103 lines (83 loc) · 2.47 KB

File metadata and controls

103 lines (83 loc) · 2.47 KB

+++ slug = "closures" title = "Closures" section = "Functions" summary = "Inner functions can remember values from an enclosing scope." doc_path = "/reference/executionmodel.html#binding-of-names" see_also = [ "functions", "lambdas", "decorators", "partial-functions", ] +++

A closure is a function that remembers names from the scope where it was created. This lets you configure behavior once and call it later.

Each call to the outer function creates a separate remembered environment. That is why double and triple can share the same code but keep different factors.

Closures are a foundation for decorators, callbacks, and small function factories.

:::program

def make_multiplier(factor):
    def multiply(value):
        return value * factor
    return multiply

double = make_multiplier(2)
print(double(5))

triple = make_multiplier(3)
print(triple(5))

late = []
for i in range(3):
    late.append(lambda: i)
print([f() for f in late])

bound = []
for i in range(3):
    bound.append(lambda i=i: i)
print([f() for f in bound])

:::

:::cell Define a function inside another function when the inner behavior needs to remember setup from the outer call. The returned function keeps access to factor.

def make_multiplier(factor):
    def multiply(value):
        return value * factor
    return multiply

double = make_multiplier(2)
print(double(5))
10

:::

:::cell Calling the outer function again creates a separate closure. triple uses the same inner code, but remembers a different factor.

triple = make_multiplier(3)
print(triple(5))
15

:::

:::cell Closures bind names, not values. Lambdas defined in a loop all reference the same loop variable, so calling them later sees its final value. Capture the value at definition time by binding it as a default argument — lambda i=i: i — so each closure remembers its own i.

late = []
for i in range(3):
    late.append(lambda: i)
print([f() for f in late])

bound = []
for i in range(3):
    bound.append(lambda i=i: i)
print([f() for f in bound])
[2, 2, 2]
[0, 1, 2]

:::

:::note

  • A closure keeps access to names from the scope where the inner function was created.
  • Each call to the outer function can create a separate remembered environment.
  • Closures are useful for callbacks, small factories, and decorators.
  • Closures bind names, not values; capture loop variables with lambda x=x: ... to freeze them at definition time. :::