我听说在Python中不能添加多行lambdas,因为它们会在语法上与Python中的其他语法结构冲突。今天在公交车上,我一直在思考这个问题,并意识到我想不出任何一个Python构造可以与多行lambdas相冲突。考虑到我对这门语言相当熟悉,这让我很惊讶。

现在,我相信Guido没有在语言中包含多行lambda是有原因的,但出于好奇:在什么情况下,包含多行lambda会有歧义?我听说的是真的吗,还是有其他原因导致Python不允许多行lambda ?


当前回答

看看下面这些:

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

这是一个lambda返回(y,[1,2,3])(因此映射只得到一个参数,导致错误)?还是返回y?或者这是语法错误,因为新行上的逗号放错了地方?巨蟒怎么知道你想要什么?

在paren中,缩进对python来说并不重要,因此不能明确地使用多行。

这只是一个简单的例子,可能还有更多的例子。

其他回答

Guido van Rossum (Python的发明者)在一篇旧博客文章中亲自回答了这个问题。 基本上,他承认这在理论上是可能的,但任何提出的解决方案都是非python的:

“但对我来说,这个谜题的任何解决方案的复杂性都是巨大的:它要求解析器(或者更准确地说,词法分析器)能够在缩进敏感和不缩进模式之间来回切换,保持先前模式的堆栈和缩进水平。从技术上讲,这些问题都可以解决(已经有一堆缩进级别可以被一般化)。但这些都不能改变我的直觉,那就是这一切都是一个精心设计的鲁布·戈德堡(Rube Goldberg)的精巧装置。”

看看下面这些:

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

这是一个lambda返回(y,[1,2,3])(因此映射只得到一个参数,导致错误)?还是返回y?或者这是语法错误,因为新行上的逗号放错了地方?巨蟒怎么知道你想要什么?

在paren中,缩进对python来说并不重要,因此不能明确地使用多行。

这只是一个简单的例子,可能还有更多的例子。

以下是几个相关的连结:

有一段时间,我一直在跟踪Reia的开发,它最初也将在Erlang之上使用Python的基于缩进的语法和Ruby块。但是,设计师最终放弃了缩进敏感性,他写的这篇文章包括了他在缩进+多行块中遇到的问题的讨论,以及他对Guido的设计问题/决策的更多欣赏:

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

另外,这里有一个关于ruby风格的Python块的有趣建议,我遇到过Guido发布了一个响应,实际上没有将它击落(虽然不确定是否有任何后续的击落):

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

让我试着解决@balpha解析问题。我会用圆括号括住多行。如果没有括号,lambda定义是贪婪的。所以in

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

返回一个函数,返回(y*z, [1,2,3])

But

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

意味着

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

func是返回y*z的多行lambda。这有用吗?

在Python3.8之后,还有另一个用于本地绑定的方法

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

For循环

lambda x: (
    y := x ** 2,
    [y := y + x for _ in range(10)],
    y
)[-1]

如果分支

lambda x: (
    y := x ** 2,
    x > 5 and [y := y + x for _ in range(10)],
    y
)[-1]

Or

lambda x: (
    y := x ** 2,
    [y := y + x for _ in range(10)] if x > 5 else None,
    y
)[-1]

While循环

import itertools as it
lambda x: (
    l := dict(y = x ** 2),
    cond := lambda: l['y'] < 100,
    body := lambda: l.update(y = l['y'] + x),
    *it.takewhile(lambda _: cond() and (body(), True)[-1], it.count()),
    l['y']
)[-1]

Or

import itertools as it
from types import SimpleNamespace as ns
lambda x: (
    l := ns(y = x ** 2),
    cond := lambda: l.y < 100,
    body := lambda: vars(l).update(y = l.y + x),
    *it.takewhile(lambda _: cond() and (body(), True)[-1], it.count()),
    l.y
)[-1]

Or

import itertools as it
lambda x: (
    y := x ** 2,
    *it.takewhile(lambda t: t[0],
    ((
    pred := y < 100,
    pred and (y := y + x))
    for _ in it.count())),
    y
)[-1]