在python中使用lambda表达式在循环内生成函数
Posted
技术标签:
【中文标题】在python中使用lambda表达式在循环内生成函数【英文标题】:Generating functions inside loop with lambda expression in python 【发布时间】:2010-12-22 21:54:35 【问题描述】:如果我列出两个函数列表:
def makeFun(i):
return lambda: i
a = [makeFun(i) for i in range(10)]
b = [lambda: i for i in range(10)]
为什么列表a
和b
不以保存方式运行?
例如:
>>> a[2]()
2
>>> b[2]()
9
【问题讨论】:
Scope of lambda functions and their parameters?的可能重复 【参考方案1】:正如其他人所说,范围界定是问题所在。请注意,您可以通过向 lambda 表达式添加一个额外的参数并为其分配一个默认值来解决此问题:
>> def makeFun(i): return lambda: i
...
>>> a = [makeFun(i) for i in range(10)]
>>> b = [lambda: i for i in range(10)]
>>> c = [lambda i=i: i for i in range(10)] # <-- Observe the use of i=i
>>> a[2](), b[2](), c[2]()
(2, 9, 2)
结果是i
现在被显式放置在限制为lambda
表达式的范围内。
【讨论】:
【参考方案2】:从技术上讲,lambda 表达式在全局范围内可见的 i
上关闭,后者最后设置为 9。这是 相同 i
是在所有 10 个 lambdas 中都提到。例如,
i = 13
print b[3]()
在makeFun
函数中,lambda 在函数调用时定义的i
上关闭。这些是十个不同i
s。
【讨论】:
好的,现在这对我来说很有意义。谢谢! 从 Python 3 开始,列表推导式现在有了自己的范围。所以改变它的值不会改变 print(b[3]()) 的输出。有关列表理解行为的更多详细信息,请参见 here【参考方案3】:一组函数 (a) 对传递的参数进行操作,另一组 (b) 对全局变量进行操作,然后将其设置为 9。检查反汇编:
>>> import dis
>>> dis.dis(a[2])
1 0 LOAD_DEREF 0 (i)
3 RETURN_VALUE
>>> dis.dis(b[2])
1 0 LOAD_GLOBAL 0 (i)
3 RETURN_VALUE
>>>
【讨论】:
【参考方案4】:增加一些清晰度(至少在我看来)
def makeFun(i): return lambda: i
a = [makeFun(i) for i in range(10)]
b = [lambda: i for i in range(10)]
a 使用 makeFun(i),它是一个带参数的函数。
b 使用 lambda: i 这是一个没有参数的函数。它使用的 i 和之前的很不一样
为了使 a 和 b 相等,我们可以让两个函数都使用无参数:
def makeFun(): return lambda: i
a = [makeFun() for i in range(10)]
b = [lambda: i for i in range(10)]
现在两个函数都使用全局 i
>>> a[2]()
9
>>> b[2]()
9
>>> i=13
>>> a[2]()
13
>>> b[2]()
13
或者(更有用)使两者都使用一个参数:
def makeFun(x): return lambda: x
a = [makeFun(i) for i in range(10)]
b = [lambda x=i: x for i in range(10)]
我故意将 i 更改为 x ,其中变量是本地的。 现在:
>>> a[2]()
2
>>> b[2]()
2
成功!
【讨论】:
【参考方案5】:python 中的 Lambda 共享创建它们的变量范围。在第一种情况下,lambda 的范围是 makeFun 的。在第二种情况下,它是全局 i
,它是 9,因为它是循环的剩余部分。
反正我是这么理解的……
【讨论】:
【参考方案6】:不错的收获。列表理解中的 lambda 每次都看到相同的本地 i
。
你可以改写为:
a = []
for i in range(10):
a.append(makefun(i))
b = []
for i in range(10):
b.append(lambda: i)
结果相同。
【讨论】:
我不确定你想说什么。在您的示例中,b[2]()
也返回 9。
我是说它等同于列表推导;不是说a和b一样。我认为拼写出的for
循环可以更容易地查看i
的来源。以上是关于在python中使用lambda表达式在循环内生成函数的主要内容,如果未能解决你的问题,请参考以下文章