2010-12-06 134 views
8

很少会遇到一些使用匿名函数的python代码,它会返回一个匿名函数......?lambda在python中返回lambda

可惜我不能找到手的例子,但它通常需要这样的形式:

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])))() 
+3

查找并显示出真实的例子;那一个在语法上不正确。 – 2010-12-06 00:12:02

+0

产生SyntaxError:无效的语法。没有意义第二lambda – joaquin 2010-12-06 00:13:14

+0

为什么有人会这样做?答:为了刺激他人? – joaquin 2010-12-06 00:16:24

回答

13

你可以使用这样的结构做讨好

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

你可以使用它像:

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

它可以用于临时占位符。假设你有一个装饰厂:

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

可以暂时用

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

更换它也可以是有用的,如果它间接地返回拉姆达:

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

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

只是因为有些事情可能并不意味着你必须使用它。

1

这可以用来提取一些常见的重复代码(当然有其他方法可以在python中实现这一点)。

也许你正在写一个记录器,并且你需要在日志字符串前添加级别。你可能会写类似:

import sys 
prefixer = lambda prefix: lambda message: sys.stderr.write(prefix + ":" + message + "\n") 
log_error = prefixer("ERROR") 
log_warning = prefixer("WARNING") 
log_info = prefixer("INFO") 
log_debug = prefixer("DEBUG") 

log_info("An informative message") 
log_error("Oh no, a fatal problem") 

这个程序打印出

INFO:An informative message 
    ERROR:Oh no, a fatal problem 
1

我做了这样的事情就在几天前禁止在单元测试套件的测试方法。

disable = lambda fn : lambda *args, **kwargs: None 

@disable 
test_method(self): 
    ... test code that I wanted to disable ... 

以后很容易重新启用它。

2
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中使用任务。不过,我们可以拨打__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])) 

Dagnamit,我可以不要放弃增加另一项任务!我知道让我们滥用默认参数。

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而不是一个函数的方式。可能是因为某些原因他不喜欢嵌套函数。我不知道。我要说的是它的糟糕的代码。 (除非有一个神秘的理由)。

0

它是最经常的 - 至少在代码我来横穿,我自己写 - 用于“冻结”一个变量与它的值在lambda点功能已创建。否则,nonlocals变量会在它们存在的范围内引用一个变量,有时会导致不希望的结果。

例如,如果我想创建的十大功能列表,每一个是从0到9的一个标量倍增也许会写这样的:

>>> a = [(lambda j: i * j) for i in range(10)] 
>>> a[9](10) 
90 

谁,如果你想使用的任何其他factoried功能你会得到相同的结果:

>>> a[1](10) 
90 

这是因为在创建拉姆达当拉姆达里面的“我”变量没有得到解决。相反,Python在“for”语句中保留对“我”的引用 - 在它创建的范围内(此引用保留在lambda函数闭包中)。当lambda被执行时,变量被评估,并且它的值是它在那个范围内的最后一个值。

当人们使用两个嵌套的lambda这样的:

>>> a = [(lambda k: (lambda j: k * j))(i) for i in range(10)] 

“我”变量durint的“for”循环的执行进行评估。它的值被传递给“k” - 并且“k”被用作我们分解的乘数函数中的非局部变量。对于i的每个值,将会有一个封闭lambda函数的不同实例,以及“k”变量的不同值。

因此,有可能实现的原意:

>>> a = [(lambda k: (lambda j: k * j))(i) for i in range(10)] 
>>> a[1](10) 
10 
>>> a[9](10) 
90 
>>>