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

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


当前回答

让我给你介绍一个光荣但可怕的技巧:

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]

其他回答

在lambda项之间传递任意数量变量的一个安全方法:

print((lambda: [
    locals().__setitem__("a", 1),
    locals().__setitem__("b", 2),
    locals().__setitem__("c", 3),
    locals().get("a") + locals().get("b") + locals().get("c")
])()[-1])

输出:6

我很内疚在我的一些更简单的项目中实践了这个肮脏的hack:

    lambda args...:( expr1, expr2, expr3, ...,
            exprN, returnExpr)[-1]

我希望你能找到一种方法保持python化,但如果你必须这样做,这比使用exec和操纵全局变量要少一些痛苦。

在Python 3.8/3.9中有赋值表达式,因此可以在lambda中大量使用 扩展功能

例如,代码

#%%
x = 1
y = 2

q = list(map(lambda t: (
    tx := t*x,
    ty := t*y,
    tx+ty
)[-1], [1, 2, 3]))

print(q)

将打印[3,6,9]

(对于仍然对这个话题感兴趣的人。)

考虑一下这一点(甚至包括在“multiline”lambda中的进一步语句中使用语句的返回值,尽管它丑陋到令人作呕;-)

>>> 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

以下是几个相关的连结:

有一段时间,我一直在跟踪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