python - 为什么匿名闭包列表与匿名封闭函数的评估列表不同?
问题描述
注意:这个概念在列表推导中的 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
是匿名封闭函数的评估列表。为什么这两个列表不同?
解决方案
推荐阅读
- discord - DiscordAPIError:未知消息 - 如何在尝试删除消息之前检查消息是否已删除
- git - 我是否成功地永久删除了 GitHub 中的一个分支(所以没有同事可以看到它)?
- python - 如何在不使用任何库的情况下在 python 中找到嵌套列表的总和?
- php - 我有一个 PHP 文件正在向我的网站提供更新,它会删除我在子域上安装的 wordpress。我怎样才能阻止这个?
- r - 为什么我会收到此错误:“$”中的意外'$'
- c++ - 调用 epoll_wait 时如何访问 epoll 上的用户上下文数据集
- r - 如何使用将规则应用于非常见列的自定义函数合并两个数据集?
- python - 使用字符串变量时动态创建表名和列名时的 SQLalchemy 属性错误
- flutter - 分配双打的 Dart 约定
- python - Socketio 在 Heroku 上发出错误请求