我听说在Python中不能添加多行lambdas,因为它们会在语法上与Python中的其他语法结构冲突。今天在公交车上,我一直在思考这个问题,并意识到我想不出任何一个Python构造可以与多行lambdas相冲突。考虑到我对这门语言相当熟悉,这让我很惊讶。
现在,我相信Guido没有在语言中包含多行lambda是有原因的,但出于好奇:在什么情况下,包含多行lambda会有歧义?我听说的是真的吗,还是有其他原因导致Python不允许多行lambda ?
我听说在Python中不能添加多行lambdas,因为它们会在语法上与Python中的其他语法结构冲突。今天在公交车上,我一直在思考这个问题,并意识到我想不出任何一个Python构造可以与多行lambdas相冲突。考虑到我对这门语言相当熟悉,这让我很惊讶。
现在,我相信Guido没有在语言中包含多行lambda是有原因的,但出于好奇:在什么情况下,包含多行lambda会有歧义?我听说的是真的吗,还是有其他原因导致Python不允许多行lambda ?
当前回答
我知道这是一个老问题,但是为了记录,这里有一种多行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
其他回答
这通常是非常丑陋的(但有时替代方案甚至更丑陋),所以一个变通的方法是创建一个大括号表达式:
lambda: (
doFoo('abc'),
doBar(123),
doBaz())
它不会接受任何任务,所以你必须事先准备好数据。 我发现这种方法很有用的地方是PySide包装器,在那里有时会有简短的回调。编写额外的成员函数将更加丑陋。通常你不需要这个。
例子:
pushButtonShowDialog.clicked.connect(
lambda: (
field1.clear(),
spinBox1.setValue(0),
diag.show())
在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]
我很内疚在我的一些更简单的项目中实践了这个肮脏的hack:
lambda args...:( expr1, expr2, expr3, ...,
exprN, returnExpr)[-1]
我希望你能找到一种方法保持python化,但如果你必须这样做,这比使用exec和操纵全局变量要少一些痛苦。
以下是几个相关的连结:
有一段时间,我一直在跟踪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
在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