PEP 3102 – 仅限关键字的参数
- 作者:
- Talin <viridia at gmail.com>
- 状态:
- 最终版
- 类型:
- 标准跟踪
- 创建日期:
- 2006年4月22日
- Python 版本:
- 3.0
- 发布历史:
- 2006年4月28日,2006年5月19日
摘要
本PEP提议改变函数参数分配给命名参数槽的方式。特别是,它允许声明“仅限关键字”参数:只能通过关键字提供且永远不会被位置参数自动填充的参数。
基本原理
当前的Python函数调用范式允许参数通过位置或关键字指定。参数可以通过名称显式填充,也可以通过位置隐式填充。
通常情况下,函数需要接受可变数量的参数。Python语言通过“可变参数”语法(*name)支持这一点,该语法指定将任何“剩余”参数作为元组传递给可变参数。
对此的一个限制是,目前,所有常规参数槽都必须在可变参数槽之前填充。
这并非总是可取的。人们可以轻易想象一个函数,它接受可变数量的参数,但也接受一个或多个以关键字参数形式出现的“选项”。目前,唯一的方法是同时定义一个可变参数(varargs)和一个“关键字”参数(**kwargs),然后手动从字典中提取所需的关键字。
规范
从语法上讲,拟议的更改相当简单。第一个更改是允许常规参数出现在可变参数之后。
def sortwords(*wordlist, case_sensitive=False):
...
此函数接受任意数量的位置参数,并且还接受一个名为“case_sensitive”的关键字选项。此选项永远不会由位置参数填充,而必须通过名称显式指定。
仅限关键字的参数不必具有默认值。由于Python要求所有参数都绑定到值,并且绑定值到仅限关键字参数的唯一方法是通过关键字,因此此类参数是“必需关键字”参数。此类参数必须由调用者提供,并且必须通过关键字提供。
第二个语法更改是允许省略可变参数的参数名称。其含义是允许那些不接受可变参数的函数使用仅限关键字的参数。
def compare(a, b, *, key=None):
...
这项更改背后的原因如下。假设一个函数接受几个位置参数以及一个关键字参数。
def compare(a, b, key=None):
...
现在,假设您想让“key”成为仅限关键字的参数。根据上述语法,您可以通过在关键字参数之前立即添加一个可变参数来实现这一点。
def compare(a, b, *ignore, key=None):
...
不幸的是,“ignore”参数也会吸收调用者可能提供的任何错误的定位参数。鉴于我们更希望任何不需要的参数引发错误,我们可以这样做:
def compare(a, b, *ignore, key=None):
if ignore: # If ignore is not empty
raise TypeError
为了方便起见,我们可以简单地省略“ignore”名称,表示“在此之后不允许任何位置参数”。
(注:在对替代语法提案进行了大量讨论之后,BDFL已宣布支持这种“单星”语法来表示位置参数的结束。)
函数调用行为
上一节描述了旧行为和新行为之间的区别。然而,拥有一个独立于旧模型的新行为描述也很有用。因此,下一节将尝试提供这样的描述。
当函数被调用时,输入参数按如下方式分配给形式参数:
- 对于每个形式参数,都有一个槽位,用于存放分配给该参数的参数值。
- 已赋值的槽位标记为“已填充”。尚未赋值的槽位视为“空”。
- 最初,所有槽位都标记为空。
- 首先分配位置参数,然后是关键字参数。
- 对于每个位置参数:
- 尝试将参数绑定到第一个未填充的参数槽。如果该槽不是可变参数槽,则将该槽标记为“已填充”。
- 如果下一个未填充的槽是可变参数槽,并且它没有名称,则这是一个错误。
- 否则,如果下一个未填充的槽是可变参数槽,则所有剩余的非关键字参数都将放入可变参数槽中。
- 对于每个关键字参数:
- 如果存在与关键字同名的参数,则将参数值分配给该参数槽。但是,如果该参数槽已填充,则这是一个错误。
- 否则,如果存在“关键字字典”参数,则将参数添加到字典中,并使用关键字名称作为字典键,除非该键已存在条目,在这种情况下这是一个错误。
- 否则,如果没有关键字字典,也没有匹配的命名参数,则这是一个错误。
- 最后:
- 如果可变参数槽尚未填充,则将其值指定为空元组。
- 对于每个剩余的空槽:如果该槽有默认值,则用默认值填充该槽。如果没有默认值,则这是一个错误。
根据当前的 Python 实现,遇到的任何错误都将通过引发 TypeError 来表示。(如果您想要不同的行为,那是另一个 PEP 的主题。)
向后兼容性
本 PEP 中指定的函数调用行为是现有行为的超集——也就是说,预计任何现有程序都将继续正常工作。
版权
本文档已置于公共领域。
来源:https://github.com/python/peps/blob/main/peps/pep-3102.rst