2010-12-06 71 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 
>>>