【问题标题】:What are "soft keywords"?什么是“软关键字”?
【发布时间】:2021-01-19 22:18:42
【问题描述】:

根据keyword module的文档,Python 3.9新增了两个成员:

  • issoftkeyword
  • softkwlist

但是,他们的文档并没有透露任何有关其目的的信息。 What's New 文章中甚至都没有提到此更改,其中通常记录了所有 API 更改。深入研究source code 最终导致pull request,其中提到“这本质上是一个内部工具”并且“软关键字仍未使用”时间>。那么 Python 的软关键字的目的是什么?

【问题讨论】:

标签: python python-3.9


【解决方案1】:

简短:软关键字仍然可以用作变量或参数名称。

PEP 622 揭示了一些亮点(强调我的):

硬关键字和软关键字的区别在于,硬关键字始终是保留字,即使在它们没有意义的位置(例如 x = class + 1),而软关键字仅在上下文中获得特殊含义。

[...] match 和 case 关键字被建议为 软关键字,以便它们分别在 match 语句或 case 块的开头被识别为关键字,但 允许在其他地方用作变量或参数名称

【讨论】:

  • 甚至是取代 622 的 PEP 634
  • PEP 634 包含相同的示例(matchcase),但没有提供关于软关键字是什么的一般解释。 PEP 622 可以。
  • 在 Python 2 中,TrueFalse 根本不是关键字:它们只是内置范围内的标识符。 asNone 都不是有效的标识符名称。 (至少,我认为 as 从一开始就是一个关键字,作为import 语句的一部分。如果它曾经是一个有效的标识符,那是在 Python 1.5 之前的某个时候。)
  • @chepner 见this issue from 2003,这实际上是我自己写的——分配给None 绝对是2003 年的SyntaxWarning,分配给as 太过分了,包括Python 2.5。
  • 在 C++ 和 C# 中也称为 contextual keywords,在 C++/CLI 中称为 Context-sensitive keywords
【解决方案2】:

我认为最好通过演示来解释这一点。 asyncawait 在 Python 3.5 和 3.6 中是软关键字,因此它们可以用作标识符:

>>> async = "spam"
>>> async def foo():
...     pass
...
>>> await = "bar"
>>> async, await
('spam', 'bar')

但在 Python 3.7 中,它们变成了正确的关键字,并且只能在有意义的特定上下文中使用:

>>> async = "123"
  File "<stdin>", line 1
    async = "123"
          ^
SyntaxError: invalid syntax
>>> async def foo():
...     pass
...
>>> await = "bar"
  File "<stdin>", line 1
    await = "bar"
          ^
SyntaxError: invalid syntax
>>> async, await
  File "<stdin>", line 1
    async, await
         ^
SyntaxError: invalid syntax

首先将它们作为软关键字引入的想法主要是为了不破坏任何使用它们作为标识符的现有代码。同样的道理也适用于即将到来的 match 关键字,例如 re.match 和数百万个项目将完全崩溃。

【讨论】:

  • 确实我忘记了 asyncawait 在当时是软关键字(尽管它们不包含在 keyword 模块中)。我的印象是新的 PEG 解析器使软关键字成为可能,所以你知道他们是如何在 Python 3.6 中实现 asyncawait 的吗?
  • 它们是用a tokenizer (lexer) hack 实现的。标记器执行前瞻并维护有关您是否在函数内部而不是解析器的上下文,并为异步和等待返回一个特殊标记。该解决方案不适用于在异步函数之外定义的异步理解(在 3.6 中无效,但在 3.7 中有效),并且对于未来的软关键字来说不是可扩展的解决方案。
【解决方案3】:

软关键字是上下文相关的关键字。例如,它允许您使用class 作为变量名,只要它不能被解释为定义类。例如,它允许使用 class 替换 cls

今天这是不可能的,因为class 是一个关键字:

>>> def a(class):
  File "<stdin>", line 1
    def a(class):
          ^

鉴于上下文,很明显用户不打算定义一个新类,而是想要一个名为 class 的标识符。

【讨论】:

  • 更重要的是,它也可以在另一个方向工作:它让您添加一个关键字到语言中,而不会使它在现有代码中用作变量名无效。赋值运算符:= 存在的一个原因是无法就现有关键字(as)的适当重用达成一致。我个人的偏好是let x = 3 in x * 2,而不是(x:=3) + 2,但由于存在破坏现有代码的风险,添加关键字的标准非常高。
  • (要清楚,我不确定这样的let 表达式是否被明确考虑过,但新关键字方面至少与为in 关键字。)
猜你喜欢
  • 2011-07-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-29
  • 2011-02-14
  • 2010-10-29
  • 2011-10-28
相关资源
最近更新 更多