Creating lambdas iteractively in Python: why does this approach work but the other one doesn't?

Question:

I’ve been trying to create a bunch of lambdas, one for each key in a dictionary, without having to do them one by one. I ended up achieving what I wanted to, but I want to understand why my first approach didn’t work, while the second one did. I assumed they would produce the exact same results… I don’t see what I’m missing!

I’ve included a small reprex below:

# approach 1 ========================================
bunch_of_funcs = {
    "func1": None,
    "func2": None,
    "func3": None,
    "func4": None,
}

for func_name in bunch_of_funcs:
    bunch_of_funcs[func_name] = lambda: print(func_name)

# now executing... prints func4 4 times
for func in bunch_of_funcs.values():
    func()

# approach 2 ========================================
def lambda_func(func_name):
    return lambda: print(func_name)

for func_name in bunch_of_funcs:
    bunch_of_funcs[func_name] = lambda_func(func_name)

# now executing... prints what i expect
for func in bunch_of_funcs.values():
    func()

EDIT: After chepner’s answer, I tried "localizing" the variable by wrapping the for loop inside of a function. I’m still getting the same result, though… Where is this global variable being created? And why is it being changed on every iteration?
My change below:

def make_lambdas(dict_of_funcs):
    for func_name in dict_of_funcs:
        dict_of_funcs[func_name] = lambda: print(func_name)

make_lambdas(bunch_of_funcs)
Asked By: Bruno Reis

||

Answers:

In both cases, your lambda-defined function wraps a name func_name. However, that name refers to two different variables. In the first case, it refers to a single global variable. In the second case, it refers to 4 different local variables, a new one for each call to lambda_func.

Answered By: chepner
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.