没有多行拉姆达在Python:为什么不呢?

问题描述 投票:268回答:11

我听到有人说,多行lambda表达式不能在Python中添加,因为他们会在Python中的其它语法结构语法冲突。我今天在公共汽车上考虑这一点,并意识到我不能想象一个Python的构建多lambda表达式与冲突。鉴于我知道的语言很好,这让我感到惊讶。

现在,我敢肯定圭多了不包括在语言多行lambda表达式的一个原因,但出于好奇:什么是其中包括一个多拉姆达是模棱两可的情况?是我所听到的真实,或者是有一些其他原因的Python不允许lambda表达式多?

python syntax lambda
11个回答
135
投票

请看下面:

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

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

在括号内的,压痕不要紧,蟒蛇,所以你不能明显与多线工作。

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


0
投票

在丑陋的黑客的问题,您可以随时使用exec的组合和常规的功能来定义这样的多的功能:

f = exec('''
def mlambda(x, y):
    d = y - x
    return d * d
''', globals()) or mlambda

您可以封装成函数此类似:

def mlambda(signature, *lines):
    exec_vars = {}
    exec('def mlambda' + signature + ':\n' + '\n'.join('\t' + line for line in lines), exec_vars)
    return exec_vars['mlambda']

f = mlambda('(x, y)',
            'd = y - x',
            'return d * d')

0
投票

我只是打了一下,要尽量做到与减少的字典理解,并拿出这一个班轮黑客:

In [1]: from functools import reduce
In [2]: reduce(lambda d, i: (i[0] < 7 and d.__setitem__(*i[::-1]), d)[-1], [{}, *{1:2, 3:4, 5:6, 7:8}.items()])                                                                                                                                                                 
Out[3]: {2: 1, 4: 3, 6: 5}

我只是试图做一样的东西在此Javascript字典理解做:https://stackoverflow.com/a/11068265


0
投票

因为lambda函数应该是一个衬里,作为其功能,an entrance, then return的最简单的形式


572
投票

吉多·范罗苏姆(Python中的发明人)回答了这个问题询问自己在an old blog post。 基本上,他承认,它在理论上是可能的,但是,任何建议的解决办法是联合国Python化:

“但对于这个难题提出的任何解决方案的复杂性是巨大的,对我说:它要求解析器(或者更准确地说,词法分析器),以便能够缩进敏感和缩进不敏感的模式之间来回切换,保持一个堆栈以前的模式和缩进的水平。从技术上说都可以解决了(已经有可能被推广缩进层次的堆叠),但这些方法都带走了我的直觉,这是所有精心Rube Goldberg contraption“。


47
投票

这通常是非常难看(但有时替代品就更难看了),所以解决方法是做一个括号表达式:

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

它不会接受任何分配的,所以你必须事先准备数据。我发现这个有用的地方是PySide包装,你有时有短暂回调。编写额外的成员函数会更加难看。通常情况下,你不需要这个。

例:

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

17
投票

一对夫妇相关链接:

有一段时间,我在下面的区域环境影响评价,这是最初将拥有Python的缩进基于使用Ruby语法的块太大,所有对二郎的顶部发展。但是,设计师卷筒上的压痕敏感性放弃,而这后,他写了一篇关于这一决定包括关于他遇到了与缩进+多行块问题的讨论,并且他的对圭多的设计议题/决定增加欣赏:

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

此外,这里是一个Ruby风情的街区在Python我碰到哪里圭多张贴的响应跑了一个有趣的建议,W / O实际拍摄下来(不知道是否有任何后续拍下来,虽然):

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


10
投票

让我给你介绍一个光荣的,但可怕的黑客:

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]


10
投票

[编辑]读this answer.它解释了为什么多拉姆达不是一回事。

简单地说,它是unpythonic。从吉多·范罗苏姆的博客文章:

我发现不可接受的任何解决方案,嵌入在一个表达式的中间基于压痕块。由于我找到声明分组替换语法(例如括号或开始/结束关键字)同样不能接受,这几乎使多行拉姆达一个无法解决的难题。

对于这个答案的其余部分。无论是使用单一号线的λ或命名功能。请不要使用exec - 我后悔曾经建议。

1You'd惊讶,你可以使用Python的一行做什么。


一种解决方法以获得多lambda函数(延期skriticos的答案):

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

它能做什么:

  • Python简化(执行)读取定界符之前的元组的每一个部件。
  • 例如,即使则使用的唯一信息是在列表(0)的最后一个项目lambda x: (functionA(), functionB(), functionC(), 0)[-1]将执行所有三个功能。
  • 通常情况下,你不能分配或使用但在exec功能,您可以(注意,它总是返回:None)在python列表或元组内声明变量。
  • 需要注意的是,除非你将变量声明为global它不会对exec函数调用的外部存在(这只是针对exec语句中lambda功能真)。
  • 例如,(lambda: exec('x=5;print(x)'))()作品,未经global声明的罚款。然而,(lambda: (exec('x=5'), exec('print(x)')))()(lambda: (exec('x=5'), x)()没有。
  • 请注意,所有global变量存储在全局命名空间,并会继续存在函数调用完成后。出于这个原因,这不是一个很好的解决方案,并应在一切可能避免,如果。 从一个lambda函数内部global函数声明exec变量保持从global命名空间是分开的。 (在Python 3.3.3测试)
  • 在元组的结尾[-1]得到最后一个索引。例如[1,2,3,4][-1]4。这样做以便仅所希望的输出值(一个或多个)被返回,而不是含有来自None功能和其它外来的值exec整个元组。

相当于多线功能:

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

6
投票

让我尝试解决@balpha解析问题。我会用括号围绕多LAMDA。如果没有括号,拉姆达的定义是贪婪的。所以在拉姆达

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。那样有用吗?


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

4
投票

我有罪练习中我的一些项目,这个肮脏的黑客是有点简单的:

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

我希望你能找到一种方式留Python的,但如果你必须这样做,这比使用EXEC和操纵全局的痛苦。

© www.soinside.com 2019 - 2024. All rights reserved.