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 需要重新设计,找到更符合 Python 风格的语法(也许可以采用其他一元运算符)。请参阅 2005 年 6 月 17 日的 python-dev 讨论 [1].
此外,最好消除那些毫无机会的替代方案。示例部分很好地突出了可读性改进。如果能添加更多示例以及实际应用的引用(而不是抽象的虚拟调用 :A
和 :B
),将更具说服力。
动机
Lambda 用于定义匿名函数,例如用作回调或(伪)延迟求值方案。通常,人们不会在合适的情况下使用 lambda,仅仅因为关键字 “lambda” 使代码看起来很复杂。在某些特殊情况下,可以省略 lambda,只需对语法进行微小且向后兼容的更改,就可以提供一种简单的方法来解决这种 “lambda 恐惧症”。
基本原理
有时人们不使用 lambda 是因为他们害怕引入一个带理论背景的术语。此提案通过省略 “lambda” 关键字本身,简化了引入无参数 lambda 的过程。实现可以通过简单地更改语法来完成,使其在一些众所周知的用例中隐式地推断出 “lambda” 关键字。特别是,添加周围的括号可以让您在任何地方指定空参数 lambda。
语法
在以下情况下,可以省略无参数 “lambda” 关键字
- 在命名参数赋值或默认值赋值中,紧接在 “=” 后面;
- 在任何表达式中,紧接在 “(” 后面;
- 在函数参数列表中,紧接在 “,” 后面;
- 在字典字面量中,紧接在 “:” 后面;(未实现)
- 在赋值语句中;(未实现)
使用示例
- 内联
if
def 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
进行一些调整,以实现语法和语义上的更改。
(需要一些语法/解析器专家才能完成完整的实现。)
以下是对 Grammar
文件的更改,以允许隐式 lambda
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
的位置。
此实现尚未完成。首先,因为 Parser 模块中的某些文件需要更新。其次,一些额外的部分尚未实现,请参阅上面的语法部分。
讨论
此功能并不高调(唯一新颖的部分是 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 的 comp.lang.python 上,Paul Rubin 首次提出删除 lambda 的想法,当时他正在讨论主题 “供审查:PEP 308 - if-then-else 表达式” [2].
参考文献
版权
本文件已归入公有领域。
来源:https://github.com/python/peps/blob/main/peps/pep-0312.rst