Python中的lambda返回lambda
我很少看到一些 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