### Question :

If I make two lists of functions:

```
def makeFun(i):
return lambda: i
a = [makeFun(i) for i in range(10)]
b = [lambda: i for i in range(10)]
```

why do lists `a`

and `b`

not behave in the save way?

For example:

```
>>> a[2]()
2
>>> b[2]()
9
```

##
Answer #1:

Technically, the lambda expression is *closed* over the `i`

that’s visible in the global scope, which is last set to 9. It’s the *same* `i`

being referred to in all 10 lambdas. For example,

```
i = 13
print b[3]()
```

In the `makeFun`

function, the lambda closes on the `i`

that’s defined when the function is invoked. Those are ten *different* `i`

s.

##
Answer #2:

As others have stated, scoping is the problem. Note that you can solve this by adding an extra argument to the lambda expression and assigning it a default value:

```
>> def makeFun(i): return lambda: i
...
>>> a = [makeFun(i) for i in range(10)]
>>> b = [lambda: i for i in range(10)]
>>> c = [lambda i=i: i for i in range(10)] # <-- Observe the use of i=i
>>> a[2](), b[2](), c[2]()
(2, 9, 2)
```

The result is that `i`

is now explicitly placed in a scope confined to the `lambda`

expression.

##
Answer #3:

One set of functions (a) operates on the argument passed and the other (b) operates on a global variable which is then set to 9. Check the disassembly:

```
>>> import dis
>>> dis.dis(a[2])
1 0 LOAD_DEREF 0 (i)
3 RETURN_VALUE
>>> dis.dis(b[2])
1 0 LOAD_GLOBAL 0 (i)
3 RETURN_VALUE
>>>
```

##
Answer #4:

To add some clarity (at least in my mind)

```
def makeFun(i): return lambda: i
a = [makeFun(i) for i in range(10)]
b = [lambda: i for i in range(10)]
```

a uses makeFun(i) which is a function with an argument.

b uses lambda: i which is a function **without** arguments. The i it uses is very different from the previous

To make a and b equal we can make both functions to use no arguments:

```
def makeFun(): return lambda: i
a = [makeFun() for i in range(10)]
b = [lambda: i for i in range(10)]
```

Now both functions use the global i

```
>>> a[2]()
9
>>> b[2]()
9
>>> i=13
>>> a[2]()
13
>>> b[2]()
13
```

Or (more useful) make both use one argument:

```
def makeFun(x): return lambda: x
a = [makeFun(i) for i in range(10)]
b = [lambda x=i: x for i in range(10)]
```

I deliberately changed i with x where the variable is local.

Now:

```
>>> a[2]()
2
>>> b[2]()
2
```

Success !

##
Answer #5:

Lambdas in python share the variable scope they’re created in. In your first case, the scope of the lambda is makeFun’s. In your second case, it’s the global `i`

, which is 9 because it’s a leftover from the loop.

That’s what I understand of it anyway…

##
Answer #6:

Nice catch. The lambda in the list comprehension is seeing the same local `i`

every time.

You can rewrite it as:

```
a = []
for i in range(10):
a.append(makefun(i))
b = []
for i in range(10):
b.append(lambda: i)
```

with the same result.