Python中没有多行Lambda:为什么不?

Python中没有多行Lambda:为什么不?,python,syntax,lambda,Python,Syntax,Lambda,我听说不能在Python中添加多行lambda,因为它们在语法上与Python中的其他语法结构冲突。我今天在公共汽车上考虑过这个问题,意识到我想不出一个多行lambda冲突的Python构造。考虑到我对这门语言相当熟悉,这让我很惊讶 现在,我确信Guido没有在语言中包含多行lambda是有原因的,但出于好奇:在什么情况下包含多行lambda是不明确的?我听到的是真的吗,或者Python不允许多行lambda还有其他原因吗?请看以下内容: map(multilambda x: y=x

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

现在,我确信Guido没有在语言中包含多行lambda是有原因的,但出于好奇:在什么情况下包含多行lambda是不明确的?我听到的是真的吗,或者Python不允许多行lambda还有其他原因吗?

请看以下内容:

map(multilambda x:
      y=x+1
      return y
   , [1,2,3])
这是一个lambda返回的
(y[1,2,3])
(因此map只获取一个参数,导致错误)?还是返回
y
?还是因为新行的逗号放错了位置而导致语法错误?Python如何知道您想要什么

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

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

Guido van Rossum(Python的发明者)亲自回答了这个问题。
基本上,他承认这在理论上是可能的,但任何提议的解决方案都不是python式的:

“但对我来说,任何针对这个难题提出的解决方案的复杂性都是巨大的:它要求解析器(或者更准确地说,lexer)能够在缩进敏感模式和缩进不敏感模式之间来回切换,保留一堆以前的模式和缩进级别。从技术上讲,这一切都可以解决(已经有一堆可以概括的缩进级别了)。但所有这些都不能消除我的直觉,那就是这一切都是精心设计的。”


两个相关链接:

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

另外,我在Python中遇到了一个关于Ruby风格块的有趣建议,Guido在其中发布了一个响应,而不是实际将其击落(但不确定是否有任何后续击落):


这通常非常难看(但有时备选方案甚至更难看),因此解决方法是制作大括号表达式:

lambda: (
    doFoo('abc'),
    doBar(123),
    doBaz())
但它不会接受任何任务,所以您必须事先准备数据。 我发现这很有用的地方是PySide包装器,在那里你有时会有很短的回调。编写额外的成员函数会更难看。通常你不需要这个

例如:

pushButtonShowDialog.clicked.connect(
    lambda: (
    field1.clear(),
    spinBox1.setValue(0),
    diag.show())
mx = lambda x, y: x if x > y \
     else y
print(mx(30, 20))

Output: 30

让我尝试解决@balpha解析问题。我会在多行lamda周围使用括号。如果没有括号,lambda定义是贪婪的。因此

map(lambda x:
      y = x+1
      z = x-1
      y*z,
    [1,2,3]))
返回一个函数,该函数返回
(y*z[1,2,3])

但是

意味着

其中func是返回y*z的多行lambda。这行吗?

[Edit]阅读它解释了为什么多行lambda不是一件事

简单地说,这是非音速的。来自Guido van Rossum的博客:

< >我发现在表达式中间嵌入一个基于压痕的块是不可接受的。因为我发现语句分组(例如括号或开始/结束关键字)的可替代语法同样不可接受,这使得多行lambda是一个不可解的难题。

(适用于仍对该主题感兴趣的任何人。)

考虑一下这一点(甚至包括在“多行”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]
关于丑陋的黑客,您可以始终使用
exec
和常规函数的组合来定义如下多行函数:

f = exec('''
def mlambda(x, y):
    d = y - x
    return d * d
''', globals()) or mlambda
let(lambda x, y: x+y)((1, 2))
您可以将其包装成如下函数:

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

我对在我的一些项目中实践这种肮脏的黑客行为感到内疚,这有点简单:

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

我希望你能找到一种保持pythonic的方法,但如果你必须这样做的话,那就不会像使用exec和操纵globals那么痛苦了。

我只是在玩一点游戏,试图用reduce来理解dict,并想出一行代码:

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}
[1]中的
from functools import reduce
在[2]中:reduce(lambda d,i:(i[0]<7和d.uu setitem_uuu(*i[:-1]),d)[-1],{},*{1:2,3:4,5:6,7:8}.items())
Out[3]:{2:1,4:3,6:5}

我只是想做与Javascript dict理解中相同的事情:

因为lambda函数应该是一行的,因为它是函数的最简单形式,
一个入口,然后返回

如果lambda函数有多行,您可以简单地使用斜杠(
\

例如:

pushButtonShowDialog.clicked.connect(
    lambda: (
    field1.clear(),
    spinBox1.setValue(0),
    diag.show())
mx = lambda x, y: x if x > y \
     else y
print(mx(30, 20))

Output: 30

我从python开始,但从Javascript开始,最明显的方法是将表达式提取为函数

例如,乘法表达式
(x*2)
被提取为函数,因此我可以使用多行:

def multiply(x):
  print('I am other line')
  return x*2

r = map(lambda x : multiply(x), [1, 2, 3, 4])
print(list(r))


如果这是如何在lambda表达式本身中执行多行操作,那么它可能无法准确回答这个问题,但是如果有人看到这个线程正在研究如何调试表达式(像我一样),我认为这将有助于这是一个更有趣的多行lambda实现
lambda args: (expr1, expr2,... exprN)
lambda args: [lambda1, lambda2, ..., lambdaN]
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
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)
from functools import reduce

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

## Output: 6
def f(x):
    y = f1(x)
    z = f2(x, y)
    return y,z
f = lambda x: (lambda y: (y, f2(x,y)))(f1(x))
let = curry(lambda args, f: f(*args))
f_lmb = lambda x: let((f1(x),), lambda y: (y, f2(x,y)))
# or:
f_lmb = lambda x: let((f1(x),))(lambda y: (y, f2(x,y)))

# even better alternative:
let = lambda *args: lambda f: f(*args)
f_lmb = lambda x: let(f1(x))(lambda y: (y, f2(x,y)))
def fib(n):
    k = 0
    fib_k, fib_k_plus_1 = 0, 1
    while k < n:
        k += 1
        fib_k_plus_1, fib_k = fib_k_plus_1 + fib_k, fib_k_plus_1
    return fib_k
def loop(first_state, condition, state_changer):
    state = first_state
    while condition(*state):
        state = state_changer(*state)
    return state

fib_lmb = lambda n:\
            loop(
              (0,0,1),
              lambda k, fib_k, fib_k_plus_1:\
                k < n,
              lambda k, fib_k, fib_k_plus_1:\
                (k+1, fib_k_plus_1, fib_k_plus_1 + fib_k))[1]
def f(x):
    try:    return len(x)
    except: return 0
# the same as:
def try_except_f(try_clause, except_clause):
    try: return try_clause()
    except: return except_clause()
f = lambda x: try_except_f(lambda: len(x), lambda: 0)
# f(-1) -> 0
# f([1,2,3]) -> 3
#%%
x = 1
y = 2

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

print(q)