Python variable scope,why does funcs prints same value?

Question:

I have this program:

funcs = { idx: lambda: print(idx) for idx in range(5) }

In essence, we have a dictionary of indices and functions:

{0: <function __main__.<dictcomp>.<lambda>()>,
 1: <function __main__.<dictcomp>.<lambda>()>,
 2: <function __main__.<dictcomp>.<lambda>()>,
 3: <function __main__.<dictcomp>.<lambda>()>,
 4: <function __main__.<dictcomp>.<lambda>()>}

However, the following function calls have the same result:

funcs[4]()
4
funcs[0]()
4

Why do I get 4 as output both times, even though I am using different inputs?

Asked By: MikiBelavista

||

Answers:

You are accessing the same object each time, since dict are not ordered, and accessing them by index does not do what you expect

funcs = {
        idx: lambda: print(idx, end=' ') for idx in range(5)
        }

for f in funcs:
    print(f, id(f))

print('#'*20)

for idx in range(5):
    print(id(funcs[idx]()))

0 1477866096
1 1477866128
2 1477866160
3 1477866192
4 1477866224
####################
4 1477430720
4 1477430720
4 1477430720
4 1477430720
4 1477430720

The previous explanation is wrong. What actually happens is this:

The lambdas were constructed using idx in range(5). When a lambda is called, no matter the caller idx parameter (i.e. it doesn’t matter what idxis insidefuncs[idx]()) the lambda is using the idx from range(5). Since the range(5) now (at its end) points to 4, that is the idx each lambda uses, resulting in all of them printing 4.

The lambda are different objects, but they still all use the current inner idx.

Here is an example that helped me:

ls=[]
for i in range(2):
    ls.append(lambda : print(i))

for f in ls:
    print(id(f), end=' ')
    f()

for i in range(3,5):
    ls.append(lambda : print(i))


for f in ls:
    print(id(f), end=' ')
    f()

44467888608 1 # 1st lambda - uses the last idx (for range was 2)
44467888336 1 # 2nd lambda - uses the last idx (for range was 2)
44467888608 4 # 1st lambda - uses the current last idx (2nd for range was 5)
44467888336 4 # 2nd lambda - uses the current last idx (2nd for range was 5)
44467921240 4 # 3rd + 4th lambdas
44467921512 4
Answered By: CIsForCookies
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.