TL;DR: Dictionary Comprehension + Early\Late Binding of Lambdas in Python is Mental
Hello,

I found a behaviour I couldn't explain when using lambdas in a dictionary comprehension so I decided to post a little Intermediate Showcase to inform you about my struggles and give you a solution, in the end (no spoilers)

I like to minify python code in my spare time to relax and it often takes some iterations for each different function or class, alongside those iterations I was golfing a function in a progress bar script I wrote a very long time ago, this is the brief description of what the function should have done: `The function has to take a list of n elements and color them green, yellow or red according to a given condition.`

This was the last *functioning* function in the process of being golfed:

    def paint(total, done, elements):
        
        color_str  = lambda x, y: f'{x}{y}\033[00m'
    
        colors = {'r'   : lambda x: color_str('\033[91m',x),
                  'g' : lambda x: color_str('\033[92m',x),
                  'y': lambda x: color_str('\033[93m',x)
                  }['g' if total == done else 'y' if total/2 &lt;= done else 'r']
    
        return [*map(colors,elements)]

I thought, that's easy, this has to be equivalent to this golfed function:

    def paint(total, done, elements):
        return [*map({'rgy'[i]:lambda x:f'\033[9{i+1}m{x}\033[00m' for i in range(len('rgy'))
               }['g' if total == done else 'y' if done &lt;= total/2 else 'r'],elements)]

*Until it's not*, in fact, while the first function outputs a correct response, the last one is **somehow** stuck on the color yellow, so I thought the dictionary comprehension wasn't working properly and thus I tried:

    dict_comp = {'rgy'[i]:lambda x:f'\033[9{i+1}m{x}\033[00m' for i in range(len('rgy'))}
    print(dict_comp)

This prompted what I thought it would prompt, a dictionary with `r`,`g` and `y` as keys and a list of lambdas in different memory locations `{'r': &lt;function &lt;dictcomp&gt;.&lt;lambda&gt; at 0x0000018D3E986200&gt;, 'g': &lt;function &lt;dictcomp&gt;.&lt;lambda&gt; at 0x0000018D3E9860E0&gt;, 'y': &lt;function &lt;dictcomp&gt;.&lt;lambda&gt; at 0x0000018D3E986050&gt;}` so I tried to print all the key and lambda pairs with a test for each lambda:

    for key, lmbd in dict_comp.items():
        print(key, lmbd(f'Testing {key}'))

This was the output:

[Horrific Minion-Colored Results](https://preview.redd.it/o216rv5pjrt81.png?width=139&amp;format=png&amp;auto=webp&amp;s=eb4882d1c3114792c06656ac59204a08f297a790)

I decided to remove the slash to check the text value of the lambda and the correct progression of `i` and this why I noticed the problem: each lambda stored the last value of `i`!

    dict_comp = {'rgy'[i]:lambda x:f'033[9{i+1}m{x}\033[00m' for i in range(len('rgy'))}
    for key, lmbd in dict_comp.items():
        print(key, lmbd(f'Testing {key}'))
    
    &gt;&gt; r 033[93mTesting r # the value after the square bracket is 93 (it's supposed to be 91)
    &gt;&gt; g 033[93mTesting g # the value after the square bracket is 93 (it's supposed to be 92)
    &gt;&gt; y 033[93mTesting y # the value after the square bracket is 93

Here's the whole code in order to try both functions:

    from time import sleep
    
    def paint(total, done, elements):
        
        color_str  = lambda x, y: f'{x}{y}\033[00m'
    
        colors     =   {'r'   : lambda x: color_str('\033[91m',x),
                        'g' : lambda x: color_str('\033[92m',x),
                        'y': lambda x: color_str('\033[93m',x)
                        }['g' if total == done else 'y' if total/2 &lt;= done else 'r']
    
        return [*map(colors,elements)]
    
    
    # UNCOMMENT THIS IN ORDER TO TEST THE FUNCTION DOWN BELOW
    """
    def paint(total, done, elements):
        return [*map({'rgy'[i]:lambda x:f'\033[9{i+1}m{x}\033[00m' for i in range(len('rgy'))
               }['g' if total == done else 'y' if done &lt;= total/2 else 'r'],elements)]
    """
    
    def CustomProgressBar(task, completeness) -&gt; None:
        size = 100 // 5
        empty  = size - completeness//5
        fill = size - empty
        
        percent  = f'{completeness:&gt;3}% '
        
        filler = f'{"═"*fill}'
        isComplete = fill==size
    
        progress_bar, percent  = paint(size,fill, [filler, percent])
        progress_bar+=f'{"─"*empty}'
    
        print(f'\r{task:&lt;25}{percent}{progress_bar}',
                end='\n' if isComplete else '')
    
    
    
    for i in range(101):
        sleep(0.05)
        CustomProgressBar('Range 0-100', i)

I then asked myself:

&gt;Why does this happen? Isn't each anonymous function different?

After some scavenger hunt in StackOverFlow (thanks you Stack for the duplicate question tootip) I found out that the issue might be in [late binding in functions and lambdas in particular](https://stackoverflow.com/questions/3431676/creating-functions-in-a-loop), so the answer, apparently, is that even if the functions are stored in a different memory location as part of the dictionary, the lambda function captures the ***NAME*** of the variable, not the ***VALUE*** of the variable and assigns the value after the dict comprehension is called, so each value becomes the last value in the loop, as the friendliest guy on StackOverFlow explains [here](https://stackoverflow.com/questions/70862614/how-does-python-dict-comprehension-work-with-lambda-functions-inside).

And so, the solution was there, after several hours of head scratches and articles about early and late bind  and (anonymous) functions in loop variables inside loops, I had to tie (or late-bind, if you will) the value name of the variable in the lambda function to the  value of the variable in the loop.

This means I had to create another value in the lambda and that the value HAS to be the last in the lambda function because it will be created as a keyword argument and lambdas respect the rule of \*args first, \*\*kwargs last.

So, the solution was finally here:

    def paint(total, done, elements):
        return [*map({'rgy'[i]:lambda x, y=i+1:f'\033[9{y}m{x}\033[00m'for i in range(len('rgy'))}['g' if total == done else 'y' if done &gt;= total/2 else 'r'],elements)]

If you have any question, you find this interesting, you have any feedback, you want to talk about Python or you just want to send me death threats because I wrote a long-ass post about lambdas and how they work in loops, HMU or comment down below.

Have fun, and happy easter:

[Easter Bunny](https://preview.redd.it/c2qo8krnmrt81.png?width=564&amp;format=png&amp;auto=webp&amp;s=354dfac6c9adada4c4e5a57d531b073aa4967968)