总结
我收到了一封来自一位同胞的电子邮件,哀叹 Python 3000 中的 reduce() 和 lambda 计划消亡。经过几次交流后,我想即使是他也同意他们可以去。这是一个总结,包括我放弃 lambda、map() 和 filter() 的原因。我预计反馈中会有大量不同意见,都来自前 Lisp 或计划的人。:-)
大约 12 年前,Python 获得了 lambda、reduce()、filter() 和 map(),这是由(我相信)一位 Lisp 黑客提供的,他错过了它们并提交了工作补丁。但是,尽管有 PR 值,我认为这些功能应该从 Python 3000 中删除。
更新:lambda、filter 和 map 将保留(后两者有小的变化,返回迭代器而不是列表)。只有reduce 会从3.0 标准库中移除。您可以从 functools 导入它。
我认为删除 filter() 和 map() 是没有争议的;filter(P, S) 几乎总是更清楚地写成 [x for x in S if P(x)],这有一个巨大的优势,即最常见的用法涉及比较谓词,例如 x==42,并定义一个 lambda 只需要读者付出更多的努力(而且 lambda 比列表理解慢)。对于 map(F, S) 更是如此,它变成了 [F(x) for x in S]。当然,在许多情况下,您可以改用生成器表达式。
为什么要放弃 lambda?大多数 Python 用户不熟悉 Lisp 或 Scheme,因此名称令人困惑;此外,人们普遍误解 lambda 可以做嵌套函数不能做的事情——我仍然记得 Laura Creighton 的 Aha!-erlebnis 在我向她展示没有区别之后!即使有一个更好的名字,我认为并排两个选择只需要程序员考虑做出与他们的程序无关的选择;没有选择会简化思考过程。此外,一旦 map()、filter() 和 reduce() 消失了,就没有很多地方需要编写非常短的本地函数了;我想到了 Tkinter 回调,但我发现回调通常应该是一些带有状态的对象的方法(玩具程序除外)。
所以现在减少()。这实际上是我一直最讨厌的一个,因为除了几个涉及 + 或 * 的例子,几乎每次我看到带有非平凡函数参数的 reduce() 调用时,我都需要拿起笔和纸在我理解 reduce() 应该做什么之前,绘制出实际输入该函数的内容。所以在我看来,reduce() 的适用性几乎仅限于关联运算符,在所有其他情况下,最好明确写出累加循环。
没有很多关联运算符。(那些是运算符 X,其中 (a X b) X c 等于 a X (b X c)。)我认为它仅限于 +、*、&、|、^ 和快捷方式和/或。我们已经有了 sum(); 我很乐意将reduce() 换成product(),这样就可以处理两个最常见的用途。按位运算符相当专业,如果需要,我们可以将快速版本放在库模块中;对于快捷布尔值,我有以下建议。
让我们将 any() 和 all() 添加到标准内置函数中,定义如下(但实现更有效):
定义任何(S):
对于 S 中的 x:
如果 x:
返回真
返回错误
全部定义(S):
对于 S 中的 x:
如果不是 x:
返回错误
返回真
将这些与生成器表达式结合起来,您可以编写如下内容:
any(x > 42 for x in S) # 如果 S 的任何元素 > 42,则为真
all(x != 0 for x in S) # 如果 S 非零,则所有元素为真
这将主要为我们返回ABC的量词:ABC 的IF EACH x IN s HAS p(x):
变成if all(p(x) for x in s):
、其IF SOME x IN s HAS p(x):
变成if any(p(x) for x in s):
和IF NO x IN s HAS p(x):
变成if not any(p(x) for x in s):
。(除了在 ABC 中,变量将被绑定并在 IF 块内可用;如果您需要在 Python 中使用它,则必须编写一个显式的 for 循环并使用 break 语句。)
我希望即使您不同意删除 reduce(),您也会同意添加 any() 和 all() 是个好主意——甚至对于 Python 2.5!