我正在尝试执行以下操作,这是我最终目标的代表性示例:
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。
这样做的正确方法是什么?
最后,你有:
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
因为 nowi
仍然从上下文中查找(现在循环已经完成,所以它是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 的范围。
yu = lambda x: i + yu(x)
这使得它yu
成为一个始终调用自身的函数,保证了没有基本情况的无限递归。
为什么?好吧,您已经构建了一个闭包,其中yu
(and ) 是循环i
所属的函数或模块中的局部变量。for
那不是你想要的;您想关闭 and 的当前值,yu
而i
不是外部变量。
我不确定你为什么一开始就使用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)
通过使包装明确,正确的方法成为最明显的方法。
当然,您可以使用lambda
insidemake_new_yu
而不会使事情变得更加混乱:
def make_new_yu(yu, i):
return lambda x: i + yu(x)
如果需要,您甚至可以将初始定义设为 a lambda
。但是,如果您坚持不使用任何 def
语句,则需要以某种方式强制将正确的值放入闭包中,例如,通过使用默认值技巧。这更容易出错——一旦你完成了它就更难阅读了。
如果您想直观地了解差异,而无需了解细节:函数体定义了一个新范围。因此,在该函数内定义函数(通过lambda
或def
)意味着您的闭包来自该新范围。
考虑到您尝试总结 0、1、2、3、4 的答案。如果这是正确的,您可以使用以下 lambda 表达式:
yu = lambda x: x + yu(x+1) if x<4 else x
因为yu(0)
它提供了 10 个结果。中断条件是x
需要保持小于 4 才能相加的值。
假设这是您想要做的,您应该省略循环以获得相当简洁的语句。
此 lambda 表达式与其他 lambda 表达式的不同之处在于根据给定参数产生不同的值(当不选择 0 作为参数 x 时,除 10 外)。
我相信我没有完全理解您的问题,但是有人可以检查他是否是这个意思吗?
我假设您不需要迭代器来生成数字列表
yu = lambda x: x[0] + yu(x[1:]) if x!=[] else 0
facto = lambda f: f if f == 0 else f + facto(f-1)
print(facto(4))