什么是“软关键词”?

a_g*_*est 102 python python-3.9

根据keyword模块的文档,Python 3.9 中添加了两个新成员:

  • issoftkeyword
  • softkwlist

然而,他们的文档并未透露任何有关其目的的信息。新功能文章中甚至没有提到此更改,通常所有 API 更改都记录在文档中。深入挖掘源代码最终会导致这个拉取请求,其中提到“这本质上是一个内部工具”“软关键字仍未使用”。那么 Python 的 soft 关键字的目的是什么?

cou*_*uka 66

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

PEP 622 说明了一些问题(重点是我的):

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

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

  • PEP 634 包含相同的示例(“match”和“case”),但没有提供软关键字是什么的一般解释。PEP 622 确实如此。 (6认同)
  • @chepner 请参阅[2003 年的这个问题](https://bugs.python.org/issue691733),这实际上是我自己写的——在 2003 年分配给 `None` 绝对是一个 `SyntaxWarning`,分配给 `as` 是最高可达 Python 2.5(包括 Python 2.5)。 (5认同)
  • 甚至是取代 622 的 [PEP 634](https://www.python.org/dev/peps/pep-0634/) (3认同)
  • 在 Python 2 中,“True”和“False”根本不是关键字:它们“只是”内置范围内的标识符。“as”和“None”都不是有效的标识符名称。(至少,我认为“as”从一开始就是一个关键字,作为“import”语句的一部分。如果它曾经是一个有效的标识符,那么它是在 Python 1.5 之前的某个时候。) (2认同)
  • @gerrit:`True`/`False`/`None`永远不可能是这里使用的意义上的软关键字;它们是表达级别的,因此它们在几乎所有情况下都是合法的;我想你可以允许它们作为属性名称(“.”上下文消除歧义),但它相当有限。只有诸如“async”、“class”、“def”、“as”、“with”等至少是语句级别的内容,出现在语句中的特定位置,其中软性将有意义地限制关键字性(它们都不是,但理论上可以使用新的 PEG 解析器将其中一些软化,以实现更具表现力的语法)。 (2认同)
  • 在 C++ 和 C# 中也称为[上下文关键字](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/contextual-keywords),以及[上下文相关关键字](https: //docs.microsoft.com/en-us/cpp/extensions/context-sensitive-keywords-cpp-component-extensions?view=msvc-160) 在 C++/CLI 中 (2认同)

ruo*_*ola 34

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

>>> async = "spam"
>>> async def foo():
...     pass
...
>>> await = "bar"
>>> async, await
('spam', 'bar')
Run Code Online (Sandbox Code Playgroud)

但是在 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
Run Code Online (Sandbox Code Playgroud)

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

  • 它们是通过[标记器(词法分析器)黑客](https://benjam.info/blog/posts/2019-09-18-python-deep-dive-tokenizer/#async-and-await)实现的。标记生成器执行前瞻操作并维护有关您是否位于函数内部(而不是解析器)的上下文,并为 async 和 wait 返回一个特殊标记。该解决方案不适用于异步函数外部定义的异步推导式(在 3.6 中无效,但在 3.7 中有效),并且不是未来软关键字的可扩展解决方案。 (2认同)

Mat*_*ndh 21

软关键字是上下文敏感的关键字。例如,class只要它不能被解释为定义类,它就允许您用作变量名。它会允许使用,以取代clsclass的例子。

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

>>> def a(class):
  File "<stdin>", line 1
    def a(class):
          ^
Run Code Online (Sandbox Code Playgroud)

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

  • 更重要的是,它也可以在另一个方向上工作:它允许您向语言“添加”关键字,而不会使其在现有代码中用作变量名称无效。赋值运算符“:=”存在的原因之一是无法就现有关键字(“as”)的适当重用达成一致。我个人的偏好是“let x = 3 in x * 2”,而不是“(x:=3) + 2”,但由于存在破坏现有代码的风险,因此为添加关键字设置了极高的门槛。 (8认同)