Python: 在求和中使用 Lambda

2 投票
5 回答
9781 浏览
提问于 2025-04-17 17:22

我正在尝试做以下事情,这个例子代表了我最终想要实现的目标:

 yu = lambda x: 0
 for i in range(0,5):
      yu = lambda x: i + yu(x)

不幸的是,当我执行时,它返回了:

RuntimeError: maximum recursion depth exceeded

当我这样做时:

print yu(0)

这个打印语句应该返回10。

正确的做法是什么呢?

5 个回答

0

考虑到你想要把0、1、2、3、4这些数字加起来。如果这样做是对的,你可以使用下面这个简单的表达式:

yu = lambda x: x + yu(x+1) if x<4 else x

当你输入yu(0)时,它会返回10作为结果。这里有一个停止的条件,就是x的值必须小于4,才能继续加起来。

如果这正是你想要的结果,那么你可以省略掉循环,这样会让代码更简洁。

这个简单的表达式和其他的不同,因为它会根据你传入的参数返回不同的值(除了当你选择0作为参数x时,它总是返回10)。

5

最后,你得到了:

yu = lambda x: i + yu(x)

但是,yu 会在程序运行时被查找,而不是在你创建这个 lambda 时查找。你应该这样做:

for i in range(0,5):
    yu = lambda x, yu=yu: i + yu(x)

不过,这样做并不会返回 10,而是返回 20

>>> yu = lambda x: 0
>>> for i in range(0,5):
...     yu = lambda x, yu=yu: i + yu(x)
... 
>>> yu(0)
20

因为现在 i 还是从上下文中查找(而此时循环已经结束,所以它的值是 4)。解决办法?把 i 也作为一个关键字参数:

for i in range(0,5):
    yu = lambda x, yu=yu, i=i: i + yu(x)

现在这样就可以了:

>>> yu = lambda x: 0
>>> for i in range(0,5):
...     yu = lambda x, yu=yu, i=i: i + yu(x)
... 
>>> yu(0)
10

这个故事的道理是什么呢?要正确地将你的上下文绑定到 lambda 的作用域中。

2
 yu = lambda x: i + yu(x)

这段话的意思是,yu变成了一个总是调用自己的函数,这样就会一直重复下去,形成无限循环,而没有一个结束的条件。

为什么会这样呢?因为你创建了一个闭包,其中yui是这个函数或模块中for循环的局部变量。这样并不是你想要的;你应该使用当前的值,而不是外部的变量。

我不太明白你为什么一开始就要用lambda。如果你想定义一个函数并给它起个名字,直接用def就可以了。

这里有一个简单的解决办法:

def yu(x): return 0
def make_new_yu(yu, i):
    def new_yu(x): return i + yu(x)
    return new_yu
for i in range(0, 5):
    yu = make_new_yu(yu, i)

通过明确地包装,正确的做法就会变得非常明显。

当然,你可以在make_new_yu里面使用lambda,这样不会让事情变得更复杂:

def make_new_yu(yu, i):
    return lambda x: i + yu(x)

如果你愿意,最开始的定义也可以用lambda。但是如果你坚持不使用任何def语句,你就需要以某种方式把正确的值放入闭包中,比如使用默认值的技巧。这种方法更容易出错,而且一旦写了之后也更难阅读。

如果你想直观地理解它们之间的区别,而不想了解太多细节:函数体定义了一个新的作用域。所以,在这个函数内部定义函数(无论是用lambda还是def)意味着你的闭包是来自那个新的作用域。

撰写回答