title: Why is a list of anonymous closures not identical to a list of evaluations of anonymous enclosing functions?
body: <p><strong>Note</strong>: This concept is touched upon in <a href="https://stackoverflow.com/questions/6076270/lambda-function-in-list-comprehensions">Lambda function in list comprehensions</a>, but not to a sufficient depth for my understanding.</p>
  
  <p>We start with an example (in Python) of a <em>closure</em>:</p>
  
  <pre><code>def enclosing_function(free_variable):
      def nested_function(x):
          return x + free_variable
      return nested_function
  
      closure = enclosing_function(1)  # closure is the "addition by 1" function
      print(closure(37) == 38)  # prints: True
  </code></pre>
  
  <p>A closure is created by evaluating an <em>enclosing function</em>. The enclosing function contains a nested function, the return value of which contains the (evaluated) free variable. Mathematically, this is equivalent to evaluating a non-empty proper subset of the input variables of a function of more than one variable. In particular, the above example is equivalent to setting y = 1 in the function f(x, y) = x + y. </p>
  
  <p>An alternative implementation is to have the enclosing function return an anonymous function. In this case, the return value is called an <em>anonymous closure</em>:</p>
  
  <pre><code>def enclosing_function(free_variable):
      return lambda x: x + free_variable
  </code></pre>
  
  <p>We also have <em>anonymous enclosing functions</em>:</p>
  
  <pre><code>print((lambda free_variable: (lambda x: x + free_variable))(1)(37))  # prints: 38
  </code></pre>
  
  <p>Now, let's set <code>NUMBER_OF_LAMBDAS = 3</code> and look at two ways of constructing a list of 
  anonymous functions:</p>
  
  <pre><code>a = [lambda x: y for y in range(NUMBER_OF_LAMBDAS)]
  
  b = [lambda x: 0, lambda x: 1, lambda x: 2]
  </code></pre>
  
  <p>One would naively assume that the lists are the same, but in fact this is not true:</p>
  
  <pre><code>for i in range(NUMBER_OF_LAMBDAS):
      z = a[i]('foo')
      print(f'a_{i}(\'foo\') = {z}')
  # Prints:
  # a_0('foo') = 2
  # a_1('foo') = 2
  # a_2('foo') = 2
  
  for i in range(NUMBER_OF_LAMBDAS):
      z = b[i]('bar')
      print(f'b_{i}(\'bar\') = {z}')
  # Prints:
  # b_0('bar') = 0
  # b_1('bar') = 1
  # b_2('bar') = 2
  </code></pre>
  
  <p>The aforementioned StackOverflow article shows that to obtain the expected behavior, one must explicitly define and evaluate an anonymous enclosing function in the list comprehension:</p>
  
  <pre><code>c = [(lambda w: (lambda x: w))(y) for y in range(NUMBER_OF_LAMBDAS)]
  
  for i in range(NUMBER_OF_LAMBDAS):
      z = c[i]('foobar')
      print(f'c_{i}(\'foobar\') = {z}')
  # Prints:
  # c_0('foobar') = 0
  # c_1('foobar') = 1
  # c_2('foobar') = 2
  </code></pre>
  
  <p><code>a</code> is a list of anonymous closures. <code>c</code> is a list of evalutions of anonymous enclosing functions. Why are these two lists different?</p>