一个月前(2月20日),一则新的 PEP 没有受到任何阻碍就被官方采纳了,这么快的速度,似乎并不多见。

然而,更为高效率的是,仅在半个月内,它的实现就被合入了代码仓。也就是说,我们最快有望在 3 天后(3月23日)发布的 3.9.0 alpha 5 版本中看到它!

Python 3.9 的发布计划:

这个 PEP 就是 PEP-614:放宽对装饰器的语法限制。

当前装饰器的语法为:

decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE

PEP-614 提议将其简化为:

decorator: '@' namedexpr_test NEWLINE

我已经把 PEP 全文翻译出来了,Github 地址:http://dwz.date/RV9

放宽对装饰器的限制,这对之前的用法没有影响,但至于会带来哪些新的好处,我还不知道有哪些现实的例子。

下面是 PEP 翻译后的核心内容摘录,先跟大家一睹为快吧:

--------------摘录分割线----------------

概要

Python 当前要求所有装饰器都由 dotted name 组成,可选地带一个调用。本 PEP 提议消除这些限制,并允许任何有效的表达式作为装饰器。

(译注:dotted name,指的是装饰器在“@”符号后是“xxx”或“xxx.yyy”这种格式。没有很好地译法,故未译。)

动机

在最初引入装饰器时,Guido表示对其语法作限制是一种偏好,而不是因为技术的要求:

我对此有一种直觉。我不确定它来自哪里,但我就是有……因此,尽管将来将语法更改为 @test 相当容易,但我仍想坚持使用更受限的形式,除非给出了真正的使用 @test 会增加可读性的用例。

尽管在实践中很少遇到问题,但是多年来,BPO问题邮件列表帖子不断出现,要求去除限制。最近的一封邮件(它促成了本提案)提供了一段很好的使用 PyQt5 库的示例代码,如果放宽现有的限制,它将变得更具可读性、地道性和可维护性。

稍作修改的示例:

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 还不支持,只能用下方的啰嗦写法):

button_0 = buttons[0]

@button_0.clicked.connect
def spam():
... button_1 = buttons[1] @button_1.clicked.connect
def eggs():
...

此外,当前的语法太过宽松,以至于无法将更复杂的装饰器表达式结合在一起。也就是说,当前的限制并没有像预期的那样去禁止任意复杂的表达式,而是使它们变得更丑陋且效率低下:

# Identity function hack:

def _(x):
return x @_(buttons[0].clicked.connect)
def spam():
... # eval hack: @eval("buttons[1].clicked.connect")
def eggs():
...

原理

允许任意表达式

在相当长的一段时间内,允许任意有效表达式的决定(而不仅仅是放宽当前的限制,如允许取下标),已被视为装饰器语法发展的下一个顺理成章的步骤。正如Guido 在另一个邮件列表讨论中所说

我觉得强制约束它没有什么道理,因为它已不再是一个普通的表达式。

若对语法进行特殊设置以允许某些有用的用法,只会使当前情况复杂化,并且几乎能肯定此过程会在将来的某个时间重复。此外,这种语法上的改变的目的之一是阻止使用上述的 eval 和反模式的 identity-function 之类的诱惑。

简而言之:如果要删除一些限制,我们应该删除所有限制。

什么算一个“表达式”

在本文档中,“表达式”一词的用法与《Python语言参考》中定义的相同。可以概括为“任何在 if、elif 和 while 块中测试为有效的内容”。

这与可能更流行的定义稍有不同,后者可以概括为“任何作为有效字符串输入给 eval 的内容”。

前一个“表达式”的定义更方便,因为它非常贴合我们的需求,并且可以重用被现有语言结构所允许的语法。与其它定义相比,它有两个细微的差异:

1、元组必须加括号

这是基于 Guido 在同一封邮件中的洞察。紧接着前面的引述:

但是我不会允许逗号,决不可能赞成这样:

@f, g
def pooh(): ...

确实,它可能甚至导致没有经验的读者得出结论,认为正在使用多个装饰器,就像它们被堆叠了一样。这里要求加括号,可以使意图变得清晰,而无需施加进一步的限制和复杂语法。

2、赋值表达式不需括号

在这里,语法的选择是明确的。PEP 572解释了为什么需要在顶级表达式语句的周围加上括号:

加入此规则是为了简化用户在赋值语句和赋值表达式之间的选择——没有令两者都生效的语法位置。

由于赋值语句在此处无效,因此赋值表达式就不必带括号。

(译注:赋值表达式,即 Assignment Expressions 或 Named Expressions,是 Python 3.8 引入的新特性,就是它引入了新的“:=”海象操作符。)

-----------------正文分割线---------------

PEP 的全文翻译已收录在 Github 的《PEP中文翻译计划》中,目前已有 20+ 篇 PEP 翻译,欢迎感兴趣的同学查阅&参与翻译。

附录:

PEP614英文:https://www.python.org/dev/peps/pep-0614/

PEP614中文:http://dwz.date/RV9

PEP中文翻译计划:https://github.com/chinesehuazhou/peps-cn

Python 3.9 新特性:任意表达式可作为装饰器!的更多相关文章

  1. Python 3.8 新特性来袭

    Python 3.8 新特性来袭 Python 3.8是Python语言的最新版本,它适合用于编写脚本.自动化以及机器学习和Web开发等各种任务.现在Python 3.8已经进入官方的beta阶段,这 ...

  2. Python 3.9 新特性速览

    国庆假期,Python 社区发布了 3.9 版本的第一个 stable release. 相比于 3.8,Python 3.9 新特性众多,但不少特性与大多数 Python"使用者" ...

  3. 乐字节-Java8新特性-Lambda表达式

    上一篇文章我们了解了Java8新特性-接口默认方法,接下来我们聊一聊Java8新特性之Lambda表达式. Lambda表达式(也称为闭包),它允许我们将函数当成参数传递给某个方法,或者把代码本身当作 ...

  4. Java8新特性-Lambda表达式是什么?

    目录 前言 匿名内部类 函数式接口 和 Lambda表达式语法 实现函数式接口并使用Lambda表达式: 所以Lambda表达式是什么? 实战应用 总结 前言 Java8新特性-Lambda表达式,好 ...

  5. Java 8 新特性 - Lambda表达式

    Lambda表达式 vs 匿名类既然lambda表达式即将正式取代Java代码中的匿名内部类,那么有必要对二者做一个比较分析.一个关键的不同点就是关键字 this.匿名类的 this 关键字指向匿名类 ...

  6. C#10新特性-lambda 表达式和方法组的改进

    C# 10 中对Lambda的语法和类型进行了多项改进: 1. Lambda自然类型 Lambda 表达式现在有时具有"自然"类型. 这意味着编译器通常可以推断出 lambda 表 ...

  7. Python之路第四天,基础(4)-装饰器,迭代器,生成器

    装饰器 装饰器(decorator)是一种高级Python语法.装饰器可以对一个函数.方法或者类进行加工.在Python中,我们有多种方法对函数和类进行加工,比如在Python闭包中,我们见到函数对象 ...

  8. python 基础之第十天(闭包,装饰器,生成器,tarfile与hashlib模块使用)

    局部变量与全局变量 局部变量:在函数里面定义的,只有当函数活动时才生效 全局变量:不在函数里面的 In [1]: x=10 In [2]: def bar(): ...: x=20 ...: prin ...

  9. Python 3 初探,第 1 部分: Python 3 的新特性

    Python 3 是 Guido van Rossum 功能强大的通用编程语言的最新版本.它虽然打破了与 2.x 版本的向后兼容性,但却清理了某些语法方面的问题.本文是系列文章中的第一篇,介绍了影响该 ...

随机推荐

  1. 用磁盘工具刻录MACOSX系统启动盘方法

    些系统盘用Toast 刻录后无法引导,建议使用磁盘工具刻录系统盘 老手可能早知道这了,仅供新手参考 在应用程序-->实用工具里找到磁盘工具,打开. 将DMG文件拖放到磁盘工具窗口,双击DMG文件 ...

  2. Python---8函数(函数的参数&递归函数)

    一.函数的参数 Python的函数定义非常简单,但灵活度却非常大.除了正常定义的必选参数外,还可以使用默认参数.可变参数和关键字参数,使得函数定义出来的接口,不但能处理复杂的参数,还可以简化调用者的代 ...

  3. 吴裕雄--天生自然HTML学习笔记:HTML 链接

    HTML 链接 HTML 使用超级链接与网络上的另一个文档相连.几乎可以在所有的网页中找到链接.点击链接可以从一张页面跳转到另一张页面. HTML 超链接(链接) HTML使用标签 <a> ...

  4. DailyRollingFileAppender-设置文件大小和备份天数

    感谢:http://byx5185.iteye.com/blog/1616034 1.重写FileAppender : package com.bankht.cis.tps.apps.tps.util ...

  5. POJ 2728 二分+最小生成树

    题意:给n个点,可以将每个点的x,y的欧几里得距离(就是坐标系里两点距离公式)看作距离,z的差值即为费用差,求的是所有最小生成树中的min(边费用和/边距离和). 思路:其实挑战P143有类似的列题, ...

  6. 前端页面设计常见的30个CSS选择器

    1. *   -->   通配符选择器 * { margin: 0; padding: 0; } 星号符会选择页面每个元素.很多开发者用它把所有margin和padding归零.这当然是快捷测试 ...

  7. HTTP接口抓包工具之Fiddler

    Fiddler的基本功能介绍: Fiddler是最强大最好用的Web调试工具之一,它能记录所有客户端和服务器的http和https请求,允许你监视,设置断点,甚至修改输入输出数据,Fiddler包含了 ...

  8. 三层交换机配置DHCP为不同VLAN分配IP地址

    三层交换的原理以及DHCP的原理,作者在这里就不详细的解释了,在这里通过一个案例来了解使用三层交换做DHCP服务器,并为不同网段分配IP地址.在生产环境中,使用路由器或交换机做DHCP服务器要常见一些 ...

  9. ubuntu 16 下安装 Ubuntu Make

    第一步:下载安装包 地址:http://ftp.gnu.org/gnu/make/ 第二步:解压 先进入存放文件目录,图示: 进行解压,图示: 解压并copy到安装目录 第三步:编译 1.查看目录, ...

  10. 纯css3配合vue实现微信语音播放效果

    前言 每次写点东西都扯两句-0-,这几天一半精力放在移动端,一半维护之前的项目.书也少看了,不过还好依旧保持一颗学习的心.对于css3我是之前有专门整理过的,因此对于原理之前也算了解.今天是项目中遇到 ...