python - 列表推导中的 Lambda 在调用时返回一个 lambda

标签 python lambda python-2.x

我正在尝试在 test.py 中的列表上迭代 lambda func,并且我想获取 lambda 的调用结果,而不是函数对象本身。但是,下面的输出真的让我很困惑。

------test.py---------
#!/bin/env python
#coding: utf-8

a = [lambda: i for i in range(5)]
for i in a:
    print i()

--------output---------
<function <lambda> at 0x7f489e542e60>
<function <lambda> at 0x7f489e542ed8>
<function <lambda> at 0x7f489e542f50>
<function <lambda> at 0x7f489e54a050>
<function <lambda> at 0x7f489e54a0c8>

我在将调用结果打印到t时修改了变量名,如下所示,一切顺利。我想知道这是怎么回事。 ?

--------test.py(update)--------
a = [lambda: i for i in range(5)]
for t in a:
    print t()

-----------output-------------
4
4
4
4
4

这种行为是 2.x 特有的,是 What do lambda function closures capture? 中描述的问题的一个特例。 .在 3.x 中,列表推导为迭代变量创建了自己的范围,因此它不能从外部修改。然而,它仍然是后期绑定(bind),所以每个print都会产生4

最佳答案

在 Python 2 中,列表解析将变量“泄漏”到外部范围:

>>> [i for i in xrange(3)]
[0, 1, 2]
>>> i
2

请注意,Python 3 上的行为有所不同:

>>> [i for i in range(3)]
[0, 1, 2]
>>> i
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'i' is not defined

当您定义 lambda 时,它绑定(bind)到变量 i,而不是第二个示例所示的当前值。 现在,当您为 i 分配新值时,lambda 将返回当前值:

>>> a = [lambda: i for i in range(5)]
>>> a[0]()
4
>>> i = 'foobar'
>>> a[0]()
'foobar'

由于循环中 i 的值是 lambda 本身,因此您将其作为返回值:

>>> i = a[0]
>>> i()
<function <lambda> at 0x01D689F0>
>>> i()()()()
<function <lambda> at 0x01D689F0>

更新:Python 2.7 示例:

Python 2.7.6 (default, Jun 22 2015, 17:58:13) 
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> a = [lambda: i for i in range(5)]
>>> for i in a:
...     print i()
... 
<function <lambda> at 0x7f1eae7f15f0>
<function <lambda> at 0x7f1eae7f1668>
<function <lambda> at 0x7f1eae7f16e0>
<function <lambda> at 0x7f1eae7f1758>
<function <lambda> at 0x7f1eae7f17d0>

在 Python 3.4 上也是如此:

Python 3.4.3 (default, Oct 14 2015, 20:28:29) 
[GCC 4.8.4] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> a = [lambda: i for i in range(5)]
>>> for i in a:
...     print(i())
... 
4
4
4
4
4

有关列表解析的变量范围更改的详细信息,请参阅 Guido 的 blogpost from 2010 .

We also made another change in Python 3, to improve equivalence between list comprehensions and generator expressions. In Python 2, the list comprehension "leaks" the loop control variable into the surrounding scope:

x = 'before'
a = [x for x in 1, 2, 3]
print x # this prints '3', not 'before'

However, in Python 3, we decided to fix the "dirty little secret" of list comprehensions by using the same implementation strategy as for generator expressions. Thus, in Python 3, the above example (after modification to use print(x) :-) will print 'before', proving that the 'x' in the list comprehension temporarily shadows but does not override the 'x' in the surrounding scope.

关于python - 列表推导中的 Lambda 在调用时返回一个 lambda,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38369470/

相关文章:

python - 使用 Python/Matlab 在图像中人为地合并非刚性运动以生成数据

python - 脚本语言解释器如何引用它们的底层函数?

python - 循环内部 lambda

python - lambda 条件?

python - 用 csv.DictWriter 写入部分行?

python - 如何设计将名称与列表中的值相关联的算法? Python

python - 为 PyDev 安装 Jython 时出错

c++ - Lambda 变量捕获

python - 从文件中读取空终止(C 风格)字符串的简洁方法?

python - 在字典列表中编码