Why do Python lambdas defined in a loop with different values all return the same result?

Before understanding why Python lambdas defined in a loop with different values all return the same result, let us first learn about Lambda expressions and the concept of late binding closures.

Python Lambda

Lambda expressions allow defining anonymous functions. A lambda function is an anonymous function i.e. a function without a name. Let us see the syntax ?

lambda arguments: expressions

The keyword lambda defines a lambda function. A lambda expression contains one or more arguments, but it can have only one expression.

Example

Let us see an example ?

myStr = "Thisisit!"
(lambda myStr : print(myStr))(myStr)
Thisisit!

The Problem: Late Binding Closures

Let's say we are finding squares using lambdas. When we define different lambdas in a loop, they all reference the same variable from the outer scope ?

squares = []
for a in range(5):
    squares.append(lambda: a**2)

print(squares[2]())  # Expected: 4, Actual: 16
print(squares[0]())  # Expected: 0, Actual: 16
print(squares[4]())  # Expected: 16, Actual: 16
16
16
16

Why This Happens

The variable a is not local to the lambdas, but is defined in the outer scope. The lambda functions access a when they are called, not when they are defined. At the end of the loop, a equals 4, so all functions return 42 = 16.

We can verify this by changing the value of a after the loop ?

squares = []
for a in range(5):
    squares.append(lambda: a**2)

a = 8  # Change the value
print(squares[2]())  # Now returns 8**2 = 64
64

Solution: Using Default Arguments

To fix this, we capture the value of a as a default argument, creating a local variable for each lambda ?

squares = []
for a in range(5):
    squares.append(lambda n=a: n**2)

print(squares[0]())  # Returns 0
print(squares[2]())  # Returns 4  
print(squares[4]())  # Returns 16
0
4
16

Alternative Solutions

Using functools.partial

from functools import partial

def square(x):
    return x**2

squares = []
for a in range(5):
    squares.append(partial(square, a))

print(squares[2]())  # Returns 4
4

Using List Comprehension

squares = [lambda n=a: n**2 for a in range(5)]

print(squares[1]())  # Returns 1
print(squares[3]())  # Returns 9
1
9

Comparison

Method Captures Value? Readability Best For
Default argument Yes Good Simple cases
functools.partial Yes Excellent Existing functions
List comprehension Yes Excellent Creating collections

Conclusion

Python lambdas in loops suffer from late binding closures they capture variables by reference, not by value. Use default arguments lambda n=a: n**2 or functools.partial to capture the current value during each iteration.

---
Updated on: 2026-03-26T21:41:12+05:30

171 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements