Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python 增强提案

PEP 457 – 位置参数的记号

作者:
Larry Hastings <larry at hastings.org>
讨论组:
Python-Dev 列表
状态:
最终
类型:
信息
创建日期:
2013-10-08

目录

概述

本 PEP 提案了一种在 Python 中用于位置参数的记号。位置参数是指没有可供外部使用的名称的参数;当调用接受位置参数的函数时,位置参数会根据其位置唯一映射到这些参数。

本 PEP 是一份信息性 PEP,描述了用于描述使用位置参数的 API(例如,在 Argument Clinic 或 inspect.Signature 对象的字符串表示中)的记号。另一个 PEP,PEP 570,提案将此记号提升为完整的 Python 语法。

基本原理

Python 一直支持位置参数。早期版本的 Python 缺乏通过名称指定参数的概念,因此所有参数自然都是位置参数。这种情况在 Python 1.0 左右发生改变,所有参数突然变成了位置或关键字参数。但是,即使在当前版本的 Python 中,许多 CPython “内置”函数仍然只接受位置参数。

在现代 Python 中实现的函数可以通过可变参数 *args 参数接受任意数量的位置参数。但是,没有 Python 语法来指定接受特定数量的位置参数。换句话说,许多内置函数的签名根本无法用 Python 语法表达。

本 PEP 提案了一种用于此类签名的记号,它可以成为向后兼容语法的基础,该语法应允许在纯 Python 代码中实现任何内置函数(有关该提案,请参见 PEP 570)。

当前 Python 中的位置参数语义

有许多内置函数只接受位置参数。结果语义很容易被 Python 程序员体验到——只需尝试调用其中一个函数,并通过名称指定其参数

>>> pow(x=5, y=3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: pow() takes no keyword arguments

此外,还有一些函数具有特别有趣的语义

  • range(),它接受其必需参数左侧的可选参数。 [2]
  • dict(),其映射/迭代器参数是可选的,并且在语义上必须是位置参数。此参数的任何外部可见名称都会遮蔽进入 **kwarg 关键字可变参数字典的名称! [1]

显然,可以通过接受 (*args, **kwargs) 并手动解析参数来在纯 Python 代码中模拟这些函数中的任何一个。但这会导致 Python 函数的签名与其实际接受的内容之间出现脱节,更不用说实现此参数解析的工作了。

动机

本 PEP 没有提案我们在 Python 中实现位置参数。本 PEP 的目标只是定义语法,以便

  • 文档可以清晰、明确且一致地表达函数参数的解释方式。
  • 此语法为将来使用保留,以防社区有一天决定将位置参数添加到语言中。
  • Argument Clinic 可以使用语法变体作为其输入的一部分来定义内置函数的参数。

当前位置参数文档状态

位置参数的文档不完整且不一致

  • 某些函数通过将它们括在嵌套方括号中来表示可选的位置参数[3]
  • 某些函数通过呈现具有不同参数数量的多个原型来表示可选的位置参数组。 [4]
  • 某些函数同时使用以上两种方法。 [2] [5]

另一个需要考虑的重要想法是:目前在文档中无法判断一个函数是否接受位置参数。 open() 接受关键字参数, ord() 不接受,但无法仅通过阅读文档来判断这是真的。

语法和语义

从“一万英尺的高度”来看,暂时忽略 *args**kwargs,函数定义的语法目前如下所示

def name(positional_or_keyword_parameters, *, keyword_only_parameters):

基于这一视角,函数的新语法如下所示

def name(positional_only_parameters, /, positional_or_keyword_parameters,
         *, keyword_only_parameters):

/ 之前的参数都是位置参数。如果在函数签名中未指定 /,则该函数不接受任何位置参数。

位置参数可以具有默认值,如果它们有默认值,则它们是可选的。没有默认值的位置参数是“必需”位置参数。

位置参数的更多语义

  • 虽然位置参数在技术上具有名称,但这些名称仅限于内部使用;位置参数永远无法通过名称从外部访问。(类似于 *args**kwargs。)
  • 如果在 / 之后存在参数,则必须在 / 之后指定逗号,就像在表示转换为关键字参数的 * 之后存在逗号一样。
  • 此语法不会影响 *args**kwargs

其他限制

Argument Clinic 使用此语法的形式来指定内置函数。它强加了理论上不必要的进一步限制,但使实现变得更容易。具体来说

  • 目前具有位置参数的函数不能具有任何其他类型的参数。(这可能会在不久的将来略微放宽。)
  • Argument Clinic 支持一种名为“可选组”的附加语法。“可选组”是一组顺序的位置参数,必须作为一组进行指定或不指定。例如,如果在 Argument Clinic 中定义了一个函数,它接受四个参数,并且所有参数都是位置参数并且在一个可选组中,那么在调用该函数时,必须指定零个参数或四个参数。这对于涵盖更多 Python 的遗留库是必要的,但这超出了本 PEP 的范围,不建议实际包含在 Python 语言中。

面向未来实现者的说明

如果我们决定在 Python 的未来版本中实现位置参数,则需要做一些额外的工作来保持其语义。问题是:如何在调用函数时通知参数未传入其值?

显而易见的解决方案:向 Python 添加一个新的单例常量,当参数未映射到参数时传入。我提案将此值命名为 undefined,并使其成为名为 Undefined 的特殊类的单例。如果位置参数在调用时没有收到参数,则其值将设置为 undefined

但这又带来了另一个问题。我们如何区分“此位置参数没有收到参数”和“调用者为此参数传入 undefined”?

最好让将 undefined 作为参数传入函数成为非法行为——例如,抛出异常。但这会降低 Python 的速度,“双方同意”规则似乎在此适用。因此,应该强烈劝阻,而不是完全禁止将其设为非法行为。

但是,应允许(并鼓励)用户函数将 undefined 作为参数的默认值。

未解决的问题

Python 中有三种类型的参数

  1. 位置参数,
  2. 位置或关键字参数,以及
  3. 关键字参数。

Python 允许函数同时具有 2 和 3。并且一些内置函数(例如 range)同时具有 1 和 3。具有 1 和 2 同时存在是否有意义?或者全部存在?

致谢

将 ‘/’ 用作位置参数和位置或关键字参数之间分隔符的功劳归功于 Guido van Rossum,他在 2012 年的提案中提出了这一想法。 [6]

将左侧可选组优先级的功劳归功于 Alyssa Coghlan。(在 PyCon US 2013 的现场交流中。)


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

最后修改日期:2023-10-11 12:05:51 GMT