首页 > 解决方案 > 将循环变量值绑定到 lambda

问题描述

将循环变量传递给 lambda 时,Python 没有修复它的值。

xs = ["a", "b", "c"]
print_statements: List[Callable[[], None]] = []
for x in xs:
    print_statements.append(lambda: print(f"The value: {x}"))

for print_statement in print_statements:
    print_statement()

// Output:
// The value: c
// The value: c
// The value: c

考虑 Java 中的相同示例:

import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args)
    {
        List<String> xs = List.of("a", "b", "c");
        List<Runnable> printStatements = new ArrayList<>();
        for (String x : xs)
        {
            printStatements.add(() -> System.out.println("The value: " + x));
        }

        for (Runnable printStatement : printStatements)
        {
            printStatement.run();
        }
    }
}

// Output:
// The value: a
// The value: b
// The value: c

我在 Java 方面有更多经验。因此,Java 程序的输出是我所期望的。在 Python 中,这对我来说是一个真正的问题,我想了解正在发生的事情。

标签: pythonfor-looplambdareference

解决方案


如何更改 Python 代码以获得与 Java 示例中相同的输出

可以将外部范围变量的值绑定到 lambda 的范围:

xs = ["a", "b", "c"]
print_statements: List[Callable[[], None]] = []
for x in xs:
    print_statements.append(lambda local_x=x: print(f"The value: {local_x}"))

# Output:
# The value: a
# The value: b
# The value: c

我仍然想知道为什么 Python 是这样设计的。


我刚刚注意到 Java 不会让您执行以下操作:

for (int i = 0; i < xs.size(); i++)
{
    printStatements.add(() -> System.out.println("The value: " + xs.get(i)));
}

编译器抱怨:Variable used in lambda expression should be final or effectively final

然后解决这个问题

for (int i = 0; i < xs.size(); i++)
{
    int finalI = i;
    printStatements.add(() -> System.out.println("The value: " + xs.get(finalI)));
}

我认为这对应于 Python 代码。Python 没有那么严格,并且允许(用 Java 术语)在 lambda 中使用不是“最终或有效最终”的变量。


推荐阅读