我听说在Python中不能添加多行lambdas,因为它们会在语法上与Python中的其他语法结构冲突。今天在公交车上,我一直在思考这个问题,并意识到我想不出任何一个Python构造可以与多行lambdas相冲突。考虑到我对这门语言相当熟悉,这让我很惊讶。
现在,我相信Guido没有在语言中包含多行lambda是有原因的,但出于好奇:在什么情况下,包含多行lambda会有歧义?我听说的是真的吗,还是有其他原因导致Python不允许多行lambda ?
我听说在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)
这将返回一个标量数字列表,因此可以使用它将多个值减少为一个。
有那么多肯定不是很有效但是如果你有约束的话,这是一个快速完成一些事情的好方法然后再把它重写成一个实际的函数。
其他回答
Guido van Rossum (Python的发明者)在一篇旧博客文章中亲自回答了这个问题。 基本上,他承认这在理论上是可能的,但任何提出的解决方案都是非python的:
“但对我来说,这个谜题的任何解决方案的复杂性都是巨大的:它要求解析器(或者更准确地说,词法分析器)能够在缩进敏感和不缩进模式之间来回切换,保持先前模式的堆栈和缩进水平。从技术上讲,这些问题都可以解决(已经有一堆缩进级别可以被一般化)。但这些都不能改变我的直觉,那就是这一切都是一个精心设计的鲁布·戈德堡(Rube Goldberg)的精巧装置。”
(对于仍然对这个话题感兴趣的人。)
考虑一下这一点(甚至包括在“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
如果lambda函数有多行,可以简单地使用斜杠(\)
例子:
mx = lambda x, y: x if x > y \
else y
print(mx(30, 20))
Output: 30
关于丑陋的黑客,你总是可以使用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')
我知道这是一个老问题,但是为了记录,这里有一种多行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