Fix Python – Creating functions (or lambdas) in a loop (or comprehension)

Question

Asked By – sharvey

I’m trying to create functions inside of a loop:

functions = []

for i in range(3):
    def f():
        return i

    # alternatively: f = lambda: i

    functions.append(f)

The problem is that all functions end up being the same. Instead of returning 0, 1, and 2, all three functions return 2:

print([f() for f in functions])
# expected output: [0, 1, 2]
# actual output:   [2, 2, 2]

Why is this happening, and what should I do to get 3 different functions that output 0, 1, and 2 respectively?

Now we will see solution for issue: Creating functions (or lambdas) in a loop (or comprehension)


Answer

You’re running into a problem with late binding — each function looks up i as late as possible (thus, when called after the end of the loop, i will be set to 2).

Easily fixed by forcing early binding: change def f(): to def f(i=i): like this:

def f(i=i):
    return i

Default values (the right-hand i in i=i is a default value for argument name i, which is the left-hand i in i=i) are looked up at def time, not at call time, so essentially they’re a way to specifically looking for early binding.

If you’re worried about f getting an extra argument (and thus potentially being called erroneously), there’s a more sophisticated way which involved using a closure as a “function factory”:

def make_f(i):
    def f():
        return i
    return f

and in your loop use f = make_f(i) instead of the def statement.

This question is answered By – Alex Martelli

This answer is collected from stackoverflow and reviewed by FixPython community admins, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0