2009-08-05 67 views
194

我聽說過,多行lambda不能在Python中添加,因爲它們會在Python中與其他語法構造語句衝突。我今天在公共汽車上想到了這一點,並意識到我無法想象多線lambdas碰撞的單個Python構造。鑑於我非常瞭解這門語言,這讓我感到驚訝。Python中沒有多行Lambda:爲什麼不呢?

現在,我確定Guido有沒有在語言中包含多行lambda表達式的原因,但出於好奇:包括多行lambda表達式的含義是什麼?我聽說過的是真的,還是有其他原因,Python不允許多行lambda表達式?

+0

** TL;博士版本:**,因爲Python是一種懶惰的語言,而不{}塊和所以這是不允許的,以保持一致的語法設計。 – Andrew 2017-08-11 15:02:48

+2

**另外:我很吃驚,沒有人在答案中提到過這一點......你可以用Python中的\角色結束行並繼續到下一行......這些信息可以取代整個問題,所以...... ** – Andrew 2017-08-11 16:48:45

回答

104

請看下面:

map(multilambda x: 
     y=x+1 
     return y 
    , [1,2,3]) 

這是返回拉姆達(y, [1,2,3])(因此映射只得到一個參數,從而導致錯誤)?或者它返回y?或者它是語法錯誤,因爲新行上的逗號放錯了位置? Python如何知道你想要什麼?

在parens中,縮進與python無關,所以你不能毫不含糊地使用多行。

這只是一個簡單的例子。

+58

如果你想從lambda返回一個元組,他們可以強制使用圓括號。國際海事組織,這應該始終強制執行,以防止這種含糊不清,但哦。 – mpen 2012-07-28 23:28:13

+12

這是一個簡單的模糊性,必須通過添加一組額外的parens來解決,這些parens已經存在於很多地方,例如,由其他參數包圍的生成器表達式,在整數文本上調用一個方法(儘管這不一定是這種情況,因爲函數名不能以數字開頭),當然也包括單行lambdas(可能是長表達式寫在多行)。多線lambda與這些案件沒有特別的區別,因此在此基礎上保證排除他們。 [這](http://stackoverflow.com/a/1233520/933416)是真正的答案。 – nmclean 2014-03-07 13:41:04

435

Guido van Rossum(Python的發明者)自己在an old blog post中自己回答了這個問題。
基本上,他承認,它在理論上是可能的,但是,任何建議的解決辦法是聯合國Python化:

「但對於這個難題提出的任何解決方案的複雜性是巨大的,對我說:它要求解析器(或者更準確地說,詞法分析器)能夠在縮進敏感模式和縮進不敏感模式之間來回切換,保持以前模式和縮進級別的堆棧。從技術上講,這一切都可以解決(已經有一堆縮進級別可以被概括),但是沒有一個能夠帶走我的直覺,認爲它全部是精心製作的Rube Goldberg contraption。「

+66

爲什麼這不是最佳答案?這不是關於技術原因,而是發明人明確指出的設計選擇。 – 2011-11-15 21:33:39

+7

@DanAbramov因爲OP可能沒有登錄多年。 – 2013-01-10 08:26:53

+7

對於那些不瞭解Rube Goldberg參考文獻的人,請參閱:http://en.wikipedia.org/wiki/Rube_Goldberg_Machine – fjsj 2013-02-09 22:06:12

15

幾個相關鏈接:

有一段時間,我在下面的區域環境影響評價,這是最初將擁有Python的基於縮進使用Ruby塊語法也都在二郎山頂的發展。但是,設計師最終放棄了縮進靈敏度,他撰寫關於該決定的文章包括討論他遇到的縮進+多行塊問題,以及他爲Guido的設計問題/決定獲得的增加的欣賞:

http://www.unlimitednovelty.com/2009/03/indentation-sensitivity-post-mortem.html

而且,這裏是在蟒蛇紅寶石風情的街區一個有趣的建議,我碰到哪裏圭多張貼W A響應跑/ O實際拍攝下來(不知道是否有任何後續拍下來,雖然) :

http://tav.espians.com/ruby-style-blocks-in-python.html

+1

+1:感謝您的鏈接。 – jfs 2009-12-07 00:07:09

30

這通常是非常難看(但有時替代品就更難看了),所以解決方法是做一個牙套表達:

lambda: (
    doFoo('abc'), 
    doBar(123), 
    doBaz()) 

它不會接受任何分配的,所以你必須做好準備數據預先。 我發現這個有用的地方是PySide包裝,你有時候有短的回調。編寫額外的成員函數會更加難看。通常你不會需要這個。

例子:

pushButtonShowDialog.clicked.connect(
    lambda: (
    field1.clear(), 
    spinBox1.setValue(0), 
    diag.show()) 
+1

我的老闆在我們的PyQt應用程序中只是要求這樣的事情。真棒! – TheGerm 2015-01-26 23:55:15

+0

感謝你們,我也在尋找一種很好的方式來使用簡短(但仍然是多行)的lambda作爲PySide UI的回調。 – 2016-11-18 03:19:44

6

讓我試圖解決@balpha解析問題。我會在多行lamda中使用括號。如果沒有括號,則lambda定義是貪婪的。因此,在

map(lambda x: 
     y = x+1 
     z = x-1 
     y*z, 
    [1,2,3])) 

拉姆達返回返回(y*z, [1,2,3])

map((lambda x: 
     y = x+1 
     z = x-1 
     y*z) 
    ,[1,2,3])) 

一個功能是指

map(func, [1,2,3]) 

其中FUNC是多拉姆達返回Ÿ* Z。那樣有用嗎?

+1

我在想,頂層應該返回'map(func,[1,2,3])',底層應該是一個錯誤,因爲map函數沒有足夠的參數。代碼中還有一些額外的括號。 – 2016-12-01 20:28:02

4

[編輯]讀取this answer.它解釋了爲什麼多線lambda不是一件事。

簡而言之,它是不刺激的。來自Guido van Rossum的博客文章:

我發現任何解決方案都不可接受,它將基於縮進的塊嵌入表達式的中間。由於我發現語句分組的其他語法(例如花括號或開始/結束關鍵字)同樣不可接受,這使得多行lambda成爲難以解決的難題。

至於這個答案的其餘部分。可以使用單行的 lambda或命名函數。請不要使用exec - 我很遺憾曾經暗示過。

你會驚訝你可以用一行python做什麼。


一種解決方法,以獲得多lambda函數(延期skriticos的答案):

(lambda n: (exec('global x; x=4; x=x+n'), x-2)[-1])(0) 

作用:

  • Python簡化(執行)的每一個組件在 之前閱讀分隔符的元組。即使則使用的唯一信息 是列表中的最後一項

  • 例如,lambda x: (functionA(), functionB(), functionC(), 0)[-1] 將執行所有三個功能(0)。

  • 通常情況下,您不能在Python或Python中使用exec函數(注意它始終返回:None)分配給變量或聲明變量。

  • 需要注意的是,除非你將變量聲明爲global它不會對exec函數調用的外部存在(這是內lambda陳述僅適用於exec功能真)。

  • 例如,(lambda: exec('x=5;print(x)'))()正常工作,沒有global聲明。但是,(lambda: (exec('x=5'), exec('print(x)')))()(lambda: (exec('x=5'), x)()不。

  • 請注意,所有 global變量都存儲在全局名稱空間中,並且在函數調用完成後將繼續存在。出於這個原因,這不是一個好的解決方案,應儘可能地避免。 global在lambda函數內部從exec函數聲明的變量與global命名空間保持獨立。 (在Python 3.3.3中測試)

  • 元組末尾的[-1]獲取最後一個索引。例如[1,2,3,4][-1]4。這樣做只會返回所需的輸出值,而不是包含來自exec函數和其他無關值的None的整個元組。

等效多線功能:

def function(n): 
    x = 4 
    x = x+n 
    return x-2 

function(0) 

方法,以避免需要一個多線拉姆達:

遞歸:

f = lambda i: 1 if i==0 or i==1 else f(i-1)+f(i-2) 

布爾是整數:

lambda a, b: [(0, 9), (2, 3)][a<4][b>3] 

迭代:

lambda x: [n**2 for n in x] #Assuming x is a list or tuple in this case 
+0

任何想法爲什麼你的代碼拋出語法錯誤? http://imgur.com/a/pWuH1 – 2016-11-30 23:00:14

+1

@AndrewAnthonyGerst該代碼似乎只能在Python 3中運行。請參閱此處運行:https://repl.it/Ed67/0 'exec'從聲明變成了聲明在Python 2中成爲Python 3中的一個函數。(很像'print')。這裏有一個SO Q/A的更多細節:http://stackoverflow.com/questions/15086040/behavior-of-exec-function-in-python-2-and-python-3 – 2016-12-01 20:17:01

+3

有沒有一種方法來討厭答案不止一次? – khajvah 2017-04-27 08:32:56

4

(對於任何人的話題仍然有興趣)

考慮這個(甚至包括了‘多行’拉姆達內進一步的陳述的返回值的使用,儘管它的醜陋嘔吐;-)

>>> def foo(arg): 
...  result = arg * 2; 
...  print "foo(" + str(arg) + ") called: " + str(result); 
...  return result; 
... 
>>> f = lambda a, b, state=[]: [ 
...  state.append(foo(a)), 
...  state.append(foo(b)), 
...  state.append(foo(state[0] + state[1])), 
...  state[-1] 
... ][-1]; 
>>> f(1, 2); 
foo(1) called: 2 
foo(2) called: 4 
foo(6) called: 12 
12 
5

讓我給你介紹一個光榮的,但可怕的黑客的點:

import types 

def _obj(): 
    return lambda: None 

def LET(bindings, body, env=None): 
    '''Introduce local bindings. 
    ex: LET(('a', 1, 
      'b', 2), 
      lambda o: [o.a, o.b]) 
    gives: [1, 2] 

    Bindings down the chain can depend on 
    the ones above them through a lambda. 
    ex: LET(('a', 1, 
      'b', lambda o: o.a + 1), 
      lambda o: o.b) 
    gives: 2 
    ''' 
    if len(bindings) == 0: 
    return body(env) 

    env = env or _obj() 
    k, v = bindings[:2] 
    if isinstance(v, types.FunctionType): 
    v = v(env) 

    setattr(env, k, v) 
    return LET(bindings[2:], body, env) 

現在你可以使用這個LET形式,例如:

map(lambda x: LET(('y', x + 1, 
        'z', x - 1), 
        lambda o: o.y * o.z), 
    [1, 2, 3]) 

這給:[0, 3, 8]

+0

最初張貼在https://gist.github.com/divs1210/d218d4b747b08751b2a232260321cdeb – divs1210 2017-06-23 20:14:18

+0

這真棒!我想我會在下次編寫Python時使用它。我主要是一個Lisp和JS程序員,並且缺乏多行lambda損害。這是獲得該方法的一種方式。 – 2017-08-02 20:58:41

相關問題