PEP 312 – 简单隐式 Lambda
- 作者:
- Roman Suzi <rnd at onego.ru>, Alex Martelli <aleaxit at gmail.com>
- 状态:
- 推迟
- 类型:
- 标准跟踪
- 创建日期:
- 2003年2月11日
- Python 版本:
- 2.4
- 发布历史:
摘要
本 PEP 提议在某些语法上没有歧义的情况下,使无参数 lambda 关键字成为可选。
推迟
BDFL 讨厌一元冒号语法。本 PEP 需要回到草图阶段,找到一种更 Pythonic 的语法(也许是另一种一元运算符)。请参见 2005 年 6 月 17 日的 python-dev 讨论 [1]。
此外,消除那些毫无机会的替代提议可能也是个好主意。示例部分很好,突出了可读性的改进。如果增加更多示例和实际参考(而不是抽象的虚拟调用 :A 和 :B),将更有说服力。
动机
Lambda 对于定义匿名函数很有用,例如用作回调或(伪)延迟评估方案。通常,lambda 在适用时却未被使用,仅仅因为关键字“lambda”使代码看起来复杂。在某些特殊情况下省略 lambda 是可能的,只需对语法进行小的向后兼容的更改,就能廉价地治疗这种“lambda 恐惧症”。
基本原理
有时人们不使用 lambda 是因为他们害怕引入一个带有理论的术语。本提案通过省略“lambda”关键字本身,使引入无参数 lambda 变得更容易。实现可以通过简单地改变语法来完成,使其在少数几个众所周知的情况下允许“lambda”关键字被隐含。特别是,添加括号允许你在任何地方指定空参数 lambda。
语法
在以下情况下,可以省略无参数“lambda”关键字
- 在命名参数赋值或默认值赋值中的“=”之后;
- 在任何表达式中的“(”之后;
- 在函数参数列表中的“,”之后;
- 在字典字面量中的“:”之后;(未实现)
- 在赋值语句中;(未实现)
使用示例
- 内联
ifdef ifelse(cond, true_part, false_part): if cond: return true_part() else: return false_part() # old syntax: print ifelse(a < b, lambda:A, lambda:B) # new syntax: print ifelse(a < b, :A, :B) # parts A and B may require extensive processing, as in: print ifelse(a < b, :ext_proc1(A), :ext_proc2(B))
- 锁定
def with(alock, acallable): alock.acquire() try: acallable() finally: alock.release() with(mylock, :x(y(), 23, z(), 'foo'))
实施
实现需要对 Python 源代码中的 Grammar/Grammar 文件进行一些调整,并对 Modules/parsermodule.c 进行一些修改以实现句法和语义上的改变。
(需要一些语法/解析器专家来完成完整的实现。)
以下是允许隐式 lambda 所需的 Grammar 更改
varargslist: (fpdef ['=' imptest] ',')* ('*' NAME [',' '**'
NAME] | '**' NAME) | fpdef ['=' imptest] (',' fpdef ['='
imptest])* [',']
imptest: test | implambdef
atom: '(' [imptestlist] ')' | '[' [listmaker] ']' |
'{' [dictmaker] '}' | '`' testlist1 '`' | NAME | NUMBER | STRING+
implambdef: ':' test
imptestlist: imptest (',' imptest)* [',']
argument: [test '='] imptest
需要三个新的非终结符:imptest 用于隐式 lambda 可能出现的位置,implambdef 用于隐式 lambda 定义本身,imptestlist 用于 imptest 可能出现的位置。
此实现尚未完成。首先,因为解析器模块中的一些文件需要更新。其次,一些额外的地方尚未实现,请参见上方的语法部分。
讨论
此功能并非高可见性功能(唯一新颖的部分是 lambda 的缺失)。此功能旨在使无参数 lambda 在语法上更具吸引力,以便在某些简单情况下提供表达式的延迟评估。本提案并非针对更高级的用例(需要 lambda 的参数)。
对于隐式 lambda 还有一种替代提议:带未使用参数的隐式 lambda。在这种情况下,由此类 lambda 定义的函数可以接受任何参数,即等同于:lambda *args: expr。这种形式将更强大。在标准库中搜索发现,此类 lambda 确实在使用中。
另一个扩展可以提供一种方法,将参数列表传递给由隐式 lambda 定义的函数。然而,这些参数需要一些特殊的名称才能被访问,并且不太可能被包含在语言中。这些参数可能的本地名称是:_、__args__、__。例如
reduce(:_[0] + _[1], [1,2,3], 0)
reduce(:__[0] + __[1], [1,2,3], 0)
reduce(:__args__[0] + __args__[1], [1,2,3], 0)
这些形式看起来不甚美观,并且在 PEP 作者看来,不足以证明在这种情况下移除 lambda 关键字是合理的。
致谢
2003年2月8日 16:39:30 -0800,Paul Rubin 在 comp.lang.python 讨论“征求意见:PEP 308 - If-then-else 表达式”线程时,首次提出了放弃 lambda 的想法 [2]。
参考资料
版权
本文档已置于公共领域。
来源: https://github.com/python/peps/blob/main/peps/pep-0312.rst
最后修改: 2025-02-01 08:59:27 GMT