Problem
What does the below code snippet print out? How can we fix the anonymous functions to behave as we’d expect?
functions = []
for i in range(10):
functions.append(lambda : i)
for f in functions:
print(f())
Solution
Method 1 - Using default argument at creation
The given code snippet will print the number 9 ten times. This happens because the anonymous functions (lambdas) capture the variable i
by reference. When the functions are eventually called in the print loop, they all refer to the final value that i
held in the for loop, which is 9.
To fix the anonymous functions so they each capture the value of i
at the time they are created, you can use a default argument in the lambda expression. This way, the value of i
will be evaluated and stored at the time the lambda is defined. Here’s the modified code:
Code
Python
functions = []
for i in range(10):
functions.append(lambda i=i: i) # i is captured as a default argument
for f in functions:
print(f())
In this version, each lambda function is given a default argument equal to the current value of i
during each iteration of the loop. As a result, when the lambdas are later called, they print the value that i
had when the lambda was created. The output will be:
0
1
2
3
4
5
6
7
8
9
Thus, the problem is solved by making a small but critical change to the lambda expression to capture the loop variable properly.
Java
Here’s how the code might look if it were written in Java using anonymous classes or lambdas:
import java.util.*;
import java.util.function.Supplier;
public class Main {
public static void main(String[] args) {
List<Supplier<Integer>> functions = new ArrayList<>();
for (int i = 0; i < 10; i++) {
functions.add(() -> i);
}
for (Supplier<Integer> f : functions) {
System.out.println(f.get());
}
}
}
To fix this, we need each lambda to capture the value of i
at the time it is created. This can be done by introducing a final variable inside the loop:
import java.util.*;
import java.util.function.Supplier;
public class Main {
public static void main(String[] args) {
List<Supplier<Integer>> functions = new ArrayList<>();
for (int i = 0; i < 10; i++) {
final int value = i;
functions.add(() -> value);
}
for (Supplier<Integer> f : functions) {
System.out.println(f.get());
}
}
}
Complexity
- ⏰ Time complexity:
O(1)
for running 10 iteration - 🧺 Space complexity:
O(1)
for capturing 10 integer values in lambda function