别院牧志知识库 别院牧志知识库
首页
  • 基础

    • 全栈之路
    • 😎Awesome资源
  • 进阶

    • Python 工匠系列
    • 高阶知识点
  • 指南教程

    • Socket 编程
    • 异步编程
    • PEP 系列
  • 面试

    • Python 面试题
    • 2022 面试记录
    • 2021 面试记录
    • 2020 面试记录
    • 2019 面试记录
    • 数据库索引原理
  • 基金

    • 基金知识
    • 基金经理
  • 细读经典

    • 德隆-三个知道
    • 孔曼子-摊大饼理论
    • 配置者说-躺赢之路
    • 资水-建立自己的投资体系
    • 反脆弱
  • Git 参考手册
  • 提问的智慧
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
首页
  • 基础

    • 全栈之路
    • 😎Awesome资源
  • 进阶

    • Python 工匠系列
    • 高阶知识点
  • 指南教程

    • Socket 编程
    • 异步编程
    • PEP 系列
  • 面试

    • Python 面试题
    • 2022 面试记录
    • 2021 面试记录
    • 2020 面试记录
    • 2019 面试记录
    • 数据库索引原理
  • 基金

    • 基金知识
    • 基金经理
  • 细读经典

    • 德隆-三个知道
    • 孔曼子-摊大饼理论
    • 配置者说-躺赢之路
    • 资水-建立自己的投资体系
    • 反脆弱
  • Git 参考手册
  • 提问的智慧
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 辨析

  • Sockets编程

  • Django

  • stackoverflow

  • Flask

  • 全栈之路

  • 面试

  • 代码片段

  • 异步编程

  • 😎Awesome资源

  • PEP

    • PEP 中文翻译计划
    • [译] PEP-8 -- 编码风格指南中文版✨✨
    • [译] PEP202--列表推导式
    • [译] PEP 255--简单的生成器
    • [译] PEP 285--添加一种布尔类型
    • [译] PEP 318--函数和方法的装饰器
    • [译] PEP 328--导入多行及绝对/相对
    • [译]pep 333 -- Python Web 服务器网关接口 v1.0
    • [译]PEP 342--增强型生成器——协程
    • [译]PEP 380--子生成器的语法
    • [译]PEP 484 -- 类型提示
    • [译] PEP 525--异步生成器
    • [译] PEP 530--异步推导式
    • [译] PEP614--放宽对装饰器的语法限制
      • 概要
      • 动机
      • 原理
        • 允许任意表达式
        • 什么算一个“表达式”
      • 规格
      • 向后兼容
      • 如何教这个
      • 参考实现
      • 版权
    • [译] PEP-312--Python 3.10 的首个 PEP 诞生,内置类型 zip() 迎来新特性
    • [译]PEP 3099--Python 3 中不会改变的事情
    • [译] PEP 3105--改 print 为函数
    • [译]PEP 3107 -- 函数注解
    • [译]PEP-3129 类装饰器
    • [译] PEP 3155--类和方法的特定名称
    • [译]pep 3333 -- Python Web 服务器网关接口 v1.0.1
  • Python工匠系列

  • 高阶知识点

  • Python 学习资源待整理
  • 设计模式

  • 好“艹蛋”的 Python 呀!
  • FIFO | 待学清单📝
  • pip 安装及使用
  • 数据分析

  • 源码阅读计划

  • OOP

  • 关于 python 中的 setup.py
  • 并行分布式框架 Celery
  • 七种武器,让你的代码提高可维护性
  • 使用 pdb 调试 Python 代码
  • 每周一个 Python 标准库
  • 🐍Python
  • PEP
佚名
2019-11-27
目录

[译] PEP614--放宽对装饰器的语法限制

PEP 原文 : https://www.python.org/dev/peps/pep-0614/ (opens new window)

PEP 标题: Relaxing Grammar Restrictions On Decorators

PEP 作者: Brandt Bucher

创建日期: 2020-02-10

合入版本: 3.9

译者 :豌豆花下猫 (opens new window)

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

# 概要

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

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

# 动机

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

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

尽管在实践中很少遇到问题,但是多年来,BPO 问题 (opens new window)和邮件列表帖子 (opens new window)不断出现,要求去除限制。最近的一封邮件 (opens new window)(它促成了本提案 (opens new window))提供了一段很好的使用 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...
1
2
3
4
5
6
7
8
9
10
11
12
13

当前,这些装饰必须重写成这样(译注:上方是假想的最优写法,但 Python 还不支持,只能用下方的啰嗦写法):

button_0 = buttons[0]

@button_0.clicked.connect
def spam():
    ...

button_1 = buttons[1]

@button_1.clicked.connect
def eggs():
    ...
1
2
3
4
5
6
7
8
9
10
11

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

# Identity function hack:

def _(x):
    return x

@_(buttons[0].clicked.connect)
def spam():
    ...

# eval hack:

@eval("buttons[1].clicked.connect")
def eggs():
    ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 原理

# 允许任意表达式

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

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

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

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

# 什么算一个“表达式”

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

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

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

# 元组必须加括号

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

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

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

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

# 赋值表达式不需括号

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

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

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

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

# 规格

当前装饰器的语法为:

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

本 PEP 提议将其简化为:

decorator: '@' namedexpr_test NEWLINE
1

# 向后兼容

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

# 如何教这个

可以继续像往常一样教装饰器;一般的 Python 程序员可能甚至不知道存在着当前的限制。

# 参考实现

作者设计了一个 CPython 实现,可以在GitHub (opens new window)上找到。

# 版权

本文档归入公共领域,或使用 CC0-1.0-Universal 许可(以较宽泛的许可为准)。

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

编辑 (opens new window)
#peps
上次更新: 2024-07-15, 08:03:22
[译] PEP 530--异步推导式
[译] PEP-312--Python 3.10 的首个 PEP 诞生,内置类型 zip() 迎来新特性

← [译] PEP 530--异步推导式 [译] PEP-312--Python 3.10 的首个 PEP 诞生,内置类型 zip() 迎来新特性→

最近更新
01
提升沟通亲和力的实用策略
03-26
02
工作
07-15
03
如何选房子
06-25
更多文章>
Theme by Vdoing | Copyright © 2019-2025 IMOYAO | 别院牧志
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式