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 可以使用语法变体作为其输入的一部分来定义内置函数的参数。
当前位置参数文档状态
位置参数的文档不完整且不一致
另一个需要考虑的重要想法是:目前在文档中无法判断一个函数是否接受位置参数。 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 中有三种类型的参数
- 位置参数,
- 位置或关键字参数,以及
- 关键字参数。
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