Skip to content

Instantly share code, notes, and snippets.

@maxcountryman
Last active December 14, 2015 05:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save maxcountryman/5035489 to your computer and use it in GitHub Desktop.
Save maxcountryman/5035489 to your computer and use it in GitHub Desktop.
Some notes on closures in Python.
>>> foo = []
>>> for i in range(10):
... foo.append(lambda: i)
>>> bar = []
>>> for i in range(10):
... # `bar.append(lambda j=i: j)` may be easier to see
... bar.append(lambda i=i: i)
>>> baz = []
>>> for i in range(10):
... baz.append((lambda: lambda i)())
>>> qux = []
>>> for i in range(10):
... # or: `qux.append((lambda j: lambda j)(i))`
... qux.append((lambda i: lambda: i)(i))
# Prints 9 9 ... 9 because the bound value of `i` is evaluated when
# the function is called, i.e. after the loop is executed, so `9`.
>>> map(lambda x: x(), foo)
[9, 9, 9, 9, 9, 9, 9, 9, 9, 9]
# However here `i` is bound in the defintion of the function, via
# named arguments. A function object is created each iteration and
# thus the value is bound each time as a default. Prints 1 2 ... 9
>>> map(lambda x: x(), bar)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# This produces the same result as the first for loop and for the
# same reason: `i` is bound to the value after the loop has
# terminated due to the closure.
>>> map(lambda x: x(), baz)
[9, 9, 9, 9, 9, 9, 9, 9, 9, 9]
# Finally this approach is similar to the JavaScript idiom. A
# function is wrapped in a function. But a variable `i` is passed
# into the first function, which in turn creates a closure over
# the wrapped function. Because the outer function is called as the
# loop is iterating and `i` is passed in, the bound value of the
# current iteration is then again bound to a new scope around the
#inner the function.
>>> map(lambda x: x(), qux)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment