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

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


当前回答

下面是一个更有趣的多行lambdas实现。这是不可能实现的,因为python使用缩进作为一种结构代码的方式。

但幸运的是,我们可以使用数组和括号禁用缩进格式。

正如一些人已经指出的,你可以这样写代码:

lambda args: (expr1, expr2,... exprN)

理论上,如果你保证从左到右求值,它是可行的,但你仍然会丢失从一个表达式传递到另一个表达式的值。

实现这个的一种方法有点啰嗦

lambda args: [lambda1, lambda2, ..., lambdaN]

每个lambda从前一个接收参数。

def let(*funcs):
    def wrap(args):
        result = args                                                                                                                                                                                                                         
        for func in funcs:
            if not isinstance(result, tuple):
                result = (result,)
            result = func(*result)
        return result
    return wrap

这个方法可以让你编写一些lisp/scheme之类的东西。

你可以这样写:

let(lambda x, y: x+y)((1, 2))

可以用一种更复杂的方法来计算斜边

lst = [(1,2), (2,3)]
result = map(let(
  lambda x, y: (x**2, y**2),
  lambda x, y: (x + y) ** (1/2)
), lst)

这将返回一个标量数字列表,因此可以使用它将多个值减少为一个。

有那么多肯定不是很有效但是如果你有约束的话,这是一个快速完成一些事情的好方法然后再把它重写成一个实际的函数。

其他回答

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

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: (
    doFoo('abc'),
    doBar(123),
    doBaz())

它不会接受任何任务,所以你必须事先准备好数据。 我发现这种方法很有用的地方是PySide包装器,在那里有时会有简短的回调。编写额外的成员函数将更加丑陋。通常你不需要这个。

例子:

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

我知道这是一个老问题,但是为了记录,这里有一种多行lambda问题的解决方案,其中一个调用的结果被另一个调用消耗。

我希望它不是超级hack,因为它只是基于标准库函数,没有使用dunder方法。

下面是一个简单的例子,我们从x = 3开始,然后在第一行加1,然后在第二行加2,得到6作为输出。

from functools import reduce

reduce(lambda data, func: func(data), [
    lambda x: x + 1,
    lambda x: x + 2
], 3)

## Output: 6

看看下面这些:

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

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

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

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

让我试着解决@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。这有用吗?