Mike Trienis bio photo

Mike Trienis

All about data product and services that scale; from design to implementation

Email Twitter LinkedIn Github Stackoverflow

An example of a closure is when a function depends on a variable outside it’s scope. A more specific definition from Stack Overflow Post states:

A closure occurs when a function has access to a local variable from an enclosing scope that has finished its execution.

def make_printer(msg):
    def printer():
        print msg
    return printer

We can see that the printer() function depends on the variable msg which is defined outside the scope of it’s function.

Late binding and bad side-effects

However, things get a bit more complicated when we have late binding. It’s indeed a gotchas and is stated in Python Guide as:

Python’s closures are late binding. This means that the values of variables used in closures are looked up at the time the inner function is called.

For example, if we are given the closure:

def multipliers():
    return [lambda x : i*x for i in range(4)]

print [m(2) for m in multipliers()] # [6, 6, 6, 6]

Then we expect the output of the print statement to be [0, 2, 4, 6] based on the element-wise operation [0*2, 1*2, 2*2, 3*2]. However, [3*2, 3*2, 3*2, 3*2] = [6, 6, 6, 6] is what is actually return. That is because i is not passed to the the lambda function until the loop for i in range(4) has been evaluated.

In order to avoid the late binding side-effect we default the i argument by:

def multipliers():
  return [lambda x, i=i : i * x for i in range(4)]

print [m(2) for m in multipliers()] # [0, 2, 4, 6]