在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)]

为什么列表ab 不以保存方式运行?

例如:

>>> 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 上关闭。这些是十个不同is。

【讨论】:

好的,现在这对我来说很有意义。谢谢! 从 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表达式在循环内生成函数的主要内容,如果未能解决你的问题,请参考以下文章

Python学习笔记010——匿名函数lambda

python lambda表达式

使用 Lambda 的 Java 8 过滤器数组

python中的zipmapreduce lambda函数的使用。

Python中的lambda表达式内的赋值

python中的zipmapreduce lambda函数的使用