您的位置:首页 > 编程语言 > Python开发

Python 3.9 新特性:任意表达式可作为装饰器!

2020-03-20 17:48 288 查看
一个月前(2月20日),一则新的 PEP 没有受到任何阻碍就被官方采纳了,这么快的速度,似乎并不多见。 然而,更为高效率的是,仅在半个月内,它的实现就被合入了代码仓。也就是说,我们最快有望在 3 天后(3月23日)发布的 3.9.0 alpha 5 版本中看到它! Python 3.9 的发布计划: ![](http://ww1.sinaimg.cn/large/68b02e3bgy1gd0eie2o07j20ig0gpmyc.jpg) 这个 PEP 就是 **PEP-614:放宽对装饰器的语法限制。** 当前装饰器的语法为: ```python decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE ``` PEP-614 提议将其简化为: ```python decorator: '@' namedexpr_test NEWLINE ``` 我已经把 PEP 全文翻译出来了,Github 地址:http://dwz.date/RV9 放宽对装饰器的限制,这对之前的用法没有影响,但至于会带来哪些新的好处,我还不知道有哪些现实的例子。 下面是 PEP 翻译后的核心内容摘录,先跟大家一睹为快吧: --------------摘录分割线---------------- ### 概要 Python 当前要求所有装饰器都由 dotted name 组成,可选地带一个调用。本 PEP 提议消除这些限制,并允许任何有效的表达式作为装饰器。 (译注:dotted name,指的是装饰器在“@”符号后是“xxx”或“xxx.yyy”这种格式。没有很好地译法,故未译。) ### 动机 在最初引入装饰器时,[Guido表示](https://mail.python.org/archives/list/python-dev%40python.org/message/P3JD24UFFPZUUDANOAI6GZAPIGY4CVK7)对其语法作限制是一种偏好,而不是因为技术的要求: > 我对此有一种直觉。我不确定它来自哪里,但我就是有……因此,尽管将来将语法更改为 @test 相当容易,但我仍想坚持使用更受限的形式,除非给出了真正的使用 @test 会增加可读性的用例。 尽管在实践中很少遇到问题,但是多年来,[BPO问题](https://bugs.python.org/issue19660)和[邮件列表帖子](https://mail.python.org/archives/list/python-ideas%40python.org/thread/UQOCJH3KOPBP7P3AVNS3OYBGZPR3V2WO/%23CAOXYF4GV76AFJNCYSYMQTBM7CIPPH5M#CAOXYF4GV76AFJNCYSYMQTBM7CIPPH5M)不断出现,要求去除限制。[最近的一封邮件](https://mail.python.org/archives/list/python-ideas%40python.org/thread/WOWD4P323DYDIGUQVWMESDWUG6QOW4MP)(它[促成了本提案](https://mail.python.org/archives/list/python-ideas%40python.org/message/FKE7ZFGUDCU5WVOE2QTD5XGMCNCOMETV))提供了一段很好的使用 `PyQt5` 库的示例代码,如果放宽现有的限制,它将变得更具可读性、地道性和可维护性。 稍作修改的示例: ```python buttons = [QPushButton(f'Button {i}') for i in range(10)] # Do stuff with the list of buttons... @buttons[0].clicked.connect def spam(): ... @buttons[1].clicked.connect def eggs(): ... # Do stuff with the list of buttons... ``` 当前,这些装饰必须重写成这样(译注:上方是假想的最优写法,但 Python 还不支持,只能用下方的啰嗦写法): ```python button_0 = buttons[0] @button_0.clicked.connect def spam(): ... button_1 = buttons[1] @button_1.clicked.connect def eggs(): ... ``` 此外,当前的语法太过宽松,以至于无法将更复杂的装饰器表达式结合在一起。也就是说,当前的限制并没有像预期的那样去禁止任意复杂的表达式,而是使它们变得更丑陋且效率低下: ```python # Identity function hack: def _(x): return x @_(buttons[0].clicked.connect) def spam(): ... # eval hack: @eval("buttons[1].clicked.connect") def eggs(): ... ``` ### 原理 #### 允许任意表达式 在相当长的一段时间内,允许任意有效表达式的决定(而不仅仅是放宽当前的限制,如允许取下标),已被视为装饰器语法发展的下一个顺理成章的步骤。正如[Guido 在另一个邮件列表讨论中所说](https://mail.python.org/archives/list/python-ideas%40python.org/message/CAOXYF4GV76AFJNCYSYMQTBM7CIPPH5M): > 我觉得强制约束它没有什么道理,因为它已不再是一个普通的表达式。 若对语法进行特殊设置以允许某些有用的用法,只会使当前情况复杂化,并且几乎能肯定此过程会在将来的某个时间重复。此外,这种语法上的改变的目的之一是阻止使用上述的 eval 和反模式的 identity-function 之类的诱惑。 简而言之:如果要删除一些限制,我们应该删除所有限制。 #### 什么算一个“表达式” 在本文档中,“表达式”一词的用法与《[Python语言参考](https://docs.python.org/3.9/reference/expressions.html%23grammar-token-expression#grammar-token-expression)》中定义的相同。可以概括为“任何在 if、elif 和 while 块中测试为有效的内容”。 这与可能更流行的[定义](https://docs.python.org/3/glossary.html%23term-expression#term-expression)稍有不同,后者可以概括为“任何作为有效字符串输入给 eval 的内容”。 前一个“表达式”的定义更方便,因为它非常贴合我们的需求,并且可以重用被现有语言结构所允许的语法。与其它定义相比,它有两个细微的差异: ##### 1、元组必须加括号 这是基于 Guido 在同一封邮件中的洞察。紧接着前面的引述: > 但是我不会允许逗号,决不可能赞成这样: > > ```python > @f, g > def pooh(): ... > ``` 确实,它可能甚至导致没有经验的读者得出结论,认为正在使用多个装饰器,就像它们被堆叠了一样。这里要求加括号,可以使意图变得清晰,而无需施加进一步的限制和复杂语法。 ##### 2、赋值表达式不需括号 在这里,语法的选择是明确的。[PEP 572](https://www.python.org/dev/peps/pep-0572)解释了为什么需要在顶级表达式语句的周围加上括号: > 加入此规则是为了简化用户在赋值语句和赋值表达式之间的选择——没有令两者都生效的语法位置。 由于赋值语句在此处无效,因此赋值表达式就不必带括号。 (译注:赋值表达式,即 Assignment Expressions 或 Named Expressions,是 Python 3.8 引入的新特性,就是它引入了新的“:=”海象操作符。) -----------------正文分割线--------------- PEP 的全文翻译已收录在 Github 的《[PEP中文翻译计划](https://github.com/chinesehuazhou/peps-cn)》中,目前已有 20+ 篇 PEP 翻译,欢迎感兴趣的同学查阅&参与翻译。 附录: PEP614英文:[https://www.python.org/dev/peps/pep-0614/](https://www.python.org/dev/peps/pep-0614/) PEP614中文:[http://dwz.date/RV9](http://dwz.date/RV9) PEP中文翻译计划:[https://github.com/chinesehuazhou/peps-cn](https://github.com/chinesehuazhou/peps-cn)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: