Following system colour scheme - Python 增强提案 Selected dark colour scheme - Python 增强提案 Selected light colour scheme - Python 增强提案

Python 增强提案

PEP 614 – 放宽装饰器语法限制

作者:
Brandt Bucher <brandt at python.org>
发起人:
Guido van Rossum <guido at python.org>
状态:
最终版
类型:
标准跟踪
创建日期:
2020年2月10日
Python 版本:
3.9
发布历史:
2020年2月11日,2020年2月18日,2020年3月3日
决议:
Python-Dev 帖子

目录

摘要

Python 目前要求所有装饰器都由一个带点名称组成,可选择后跟一个函数调用。本 PEP 建议取消这些限制,允许装饰器为任何有效表达式。

动机

当装饰器首次引入时,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...

目前,这些装饰必须重写为类似以下形式:

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 和恒等函数反模式等 hack 的诱惑。

简而言之:如果我们要移除一些任意的限制,我们就应该移除*所有*的限制。

什么是“表达式”

在本文档中,“表达式”一词的定义与《Python 语言参考》中相同。可以概括为“任何在 ifelifwhile 块中作为测试有效的内容”。这与一个可能更流行的定义略有不同,后者可以概括为“任何作为字符串输入 eval 有效的内容”。

“表达式”的这个定义很方便,因为它很好地满足了我们的需求,并且重用了现有语言构造的允许语法。它与另一个定义有两个细微的区别:

元组显示*必须*用括号括起来

这基于 Guido 在同一封邮件中提出的一个观察。紧接着上面:

虽然我不允许逗号——不可能这样
@f, g
def pooh(): ...

能讲得通。

事实上,它甚至可能导致经验不足的读者认为正在应用多个装饰器,就好像它们堆叠在一起一样。在这里要求使用括号可以清晰地表达(诚然是毫无意义的)意图,而不会施加进一步的限制和语法复杂性。

命名表达式*不需要*用括号括起来

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

包含此规则是为了简化用户在赋值语句和赋值表达式之间的选择——不存在两者都有效的语法位置。

由于此处赋值语句无效,赋值表达式不应不必要地加上括号。

规范

装饰器的语法目前是:

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

本 PEP 建议将其简化为:

decorator: '@' namedexpr_test NEWLINE

向后兼容性

这个新语法与现有语法完全向后兼容。

如何教授

装饰器可以继续像以往一样教授;普通的 Python 程序员可能并不知道当前存在这些限制。

参考实现

作者已编写了 CPython 实现


来源:https://github.com/python/peps/blob/main/peps/pep-0614.rst

最后修改:2025-02-01 08:59:27 GMT