2

可能的重复:
功能制作

>>> g=lambda x:x+1
>>> composition=lambda f,g:(lambda x:f(g(x)))
>>> f=g
>>> f=composition(f,g)
>>> f(9)
11
>>> f=composition(f,g)
>>> f=composition(f,g)
>>> f=composition(f,g)
>>> f(9)
14

我没有使用函数 composition(f,g) ,而是执行了以下操作

>>> f=g
>>> f=lambda x:f(g(x))
>>> f(8)
RuntimeError: maximum recursion depth exceeded

我只是打算用相应的 lambda 表达式替换函数组合。我对为什么 f=composition(f,g) 不产生递归但 f=lambda x:f(g(x)) 产生递归感到困惑。

4

2 回答 2

2

对于第一个:

当您调用 时composition(f, g),您正在围绕这些变量的内容创建一个闭包。返回的 lambda 正在寻找变量名fg在其本地范围内 - 它们都是g对在第一行创建的 lambda 的引用。

对于第二个:

在第二个中,当f被调用时,它会f在其“本地”范围内查找,这实际上是全局范围 - 并找到自己,从而创建无限递归。

这里的关键是查找f发生在执行时,而不是在定义 lambda 时。

于 2012-09-14T21:25:15.613 回答
1

当你写这个:

f=lambda x:f(g(x))

生成的 lambda 表示“在调用 x 范围内的任何 g 的结果上调用范围内的任何 f”。

当你写这个:

f=composition(f, g)

结果函数的意思是“调用组合的第一个参数是调用组合的第二个参数的结果”。

我不确定您需要更好地理解哪一部分细节才能弄清楚这一点,但我会猜测一下。Python 中的参数传递总是通过引用,而不是通过名称。因此,当您调用 composition(f, g) 时,您传入的是 f 所指的函数对象,而不是“变量”f。但是当你定义一个 lambda 时,它只发生在范围内,所以你指的是 f 本身。

附带说明一下,这也是 Guido 不喜欢人们使用 lambda 语法的部分原因。如果您像这样重写代码,发生的事情会更加明显:

def g(x): return x+1
def composition(f,g):
  def composed(x): return f(g(x))
  return composed
f=g
f=composition(f,g)
于 2012-09-14T21:27:02.817 回答