Python中的lambda返回lambda

13 投票
8 回答
7993 浏览
提问于 2025-04-16 08:05

我很少看到一些 Python 代码使用匿名函数,而且这个匿名函数还会返回另一个匿名函数……?

不幸的是,我手头找不到例子,但通常它的形式是这样的:

g = lambda x,c: x**c lambda c: c+1

为什么会有人这样做呢?也许你可以给个合理的例子(我不太确定我做的例子是否有道理)。

编辑:这里有一个例子:

swap = lambda a,x,y:(lambda f=a.__setitem__:(f(x,(a[x],a[y])),
       f(y,a[x][0]),f(x,a[x][1])))()

8 个回答

2

这可以用作临时占位符。假设你有一个装饰器工厂:

@call_logger(log_arguments=True, log_return=False)
def f(a, b):
    pass

你可以暂时用以下内容替换它:

call_logger = lambda *a, **kw: lambda f: f

如果它间接返回一个lambda表达式,这也会很有用:

import collections
collections.defaultdict(lambda: collections.defaultdict(lambda: collections.defaultdict(int)))

在Python控制台中创建可调用的工厂时,这也很有用。

而且,仅仅因为某件事是可能的,并不意味着你必须使用它。

4
swap = lambda a,x,y:(lambda f=a.__setitem__:(f(x,(a[x],a[y])),
       f(y,a[x][0]),f(x,a[x][1])))()

你看到最后的那个()了吗?里面的lambda并不是被返回,而是被调用了。

这个函数的作用相当于

def swap(a, x, y):
     a[x] = (a[x], a[y])
     a[y] = a[x][0]
     a[x] = a[x][1]

但是假设我们想在一个lambda里做这个。我们不能在lambda中使用赋值。不过,我们可以调用__setitem__来达到同样的效果。

def swap(a, x, y):
     a.__setitem__(x, (a[x], a[y]))
     a.__setitem__(y, a[x][0])
     a.__setitem__(x, a[x][1])

不过在lambda中,我们只能有一个表达式。但是因为这些都是函数调用,我们可以把它们放在一个元组里。

def swap(a, x, y):
     (a.__setitem__(x, (a[x], a[y])),
     a.__setitem__(y, a[x][0]),
     a.__setitem__(x, a[x][1]))

不过,所有这些__setitem__让我觉得很烦,所以我们把它们提取出来:

def swap(a, x, y):
     f = a.__setitem__
     (f(x, (a[x], a[y])),
     f(y, a[x][0]),
     f(x, a[x][1]))

真是的,我不能再加一个赋值了!我知道了,咱们可以利用默认参数。

def swap(a, x, y):
     def inner(f = a.__setitem__):
         (f(x, (a[x], a[y])),
         f(y, a[x][0]),
         f(x, a[x][1]))
     inner()

好了,让我们切换到lambda:

swap = lambda a, x, y: lambda f = a.__setitem__: (f(x, (a[x], a[y])), f(y, a[x][0]),  f(x, a[x][1]))()

这又把我们带回了最初的表达式(加减一些拼写错误)

这一切都回到了这个问题:为什么?

这个函数应该实现成

def swap(a, x, y):
    a[x],a[y] = a[y],a[x]

原作者为了使用lambda而不是函数,真是费了不少劲。可能他出于某种原因不喜欢嵌套函数。我不知道。我要说的是,这代码不好。(除非有什么神秘的理由。)

19

你可以用这样的结构来实现 柯里化

curry = lambda f, a: lambda x: f(a, x)

你可能会这样使用它:

>>> add = lambda x, y: x + y
>>> add5 = curry(add, 5)
>>> add5(3)
8

撰写回答