首页 > 解决方案 > 为什么匿名闭包列表与匿名封闭函数的评估列表不同?

问题描述

注意:这个概念在列表推导中的 Lambda 函数中有所涉及,但对我的理解来说还不够深入。

我们从一个闭包的例子(在 Python 中)开始:

def enclosing_function(free_variable):
    def nested_function(x):
        return x + free_variable
    return nested_function

    closure = enclosing_function(1)  # closure is the "addition by 1" function
    print(closure(37) == 38)  # prints: True

闭包是通过评估封闭函数来创建的。封闭函数包含一个嵌套函数,其返回值包含(评估的)自由变量。在数学上,这相当于评估一个以上变量的函数的输入变量的非空真子集。特别是,上面的例子等价于在函数 f(x, y) = x + y 中设置 y = 1。

另一种实现是让封闭函数返回一个匿名函数。在这种情况下,返回值称为匿名闭包

def enclosing_function(free_variable):
    return lambda x: x + free_variable

我们还有匿名封闭函数

print((lambda free_variable: (lambda x: x + free_variable))(1)(37))  # prints: 38

现在,让我们设置NUMBER_OF_LAMBDAS = 3并查看构造匿名函数列表的两种方法:

a = [lambda x: y for y in range(NUMBER_OF_LAMBDAS)]

b = [lambda x: 0, lambda x: 1, lambda x: 2]

人们会天真地假设这些列表是相同的,但实际上这不是真的:

for i in range(NUMBER_OF_LAMBDAS):
    z = a[i]('foo')
    print(f'a_{i}(\'foo\') = {z}')
# Prints:
# a_0('foo') = 2
# a_1('foo') = 2
# a_2('foo') = 2

for i in range(NUMBER_OF_LAMBDAS):
    z = b[i]('bar')
    print(f'b_{i}(\'bar\') = {z}')
# Prints:
# b_0('bar') = 0
# b_1('bar') = 1
# b_2('bar') = 2

前面提到的 StackOverflow 文章表明,要获得预期的行为,必须在列表推导中显式定义和评估一个匿名封闭函数:

c = [(lambda w: (lambda x: w))(y) for y in range(NUMBER_OF_LAMBDAS)]

for i in range(NUMBER_OF_LAMBDAS):
    z = c[i]('foobar')
    print(f'c_{i}(\'foobar\') = {z}')
# Prints:
# c_0('foobar') = 0
# c_1('foobar') = 1
# c_2('foobar') = 2

a是一个匿名闭包列表。c是匿名封闭函数的评估列表。为什么这两个列表不同?

标签: pythonclosuresfirst-class-functions

解决方案


推荐阅读