PEP-3102 建议了 Keyword-Only Arguments,并且在 Python3 中实现。本文试着在 Python 函数参数的基本理解 基础上,更深入的理解 Keyword-Only Arguments.
普通用法
在 位置参数 和 关键字参数 中我们看到,普通情形下,一个参数既可以通过位置捕获,也可以直接用名称捕获。
举个例子:
>>> def f(a):
... print(a)
...
>>> f(1) # 通过位置隐式地捕获
1
>>> f(a=1) # 通过 Keyword Arguments 形式显式地提供
1
>>>
定义
Keyword-Only Arguments,意思是这种参数只能通过形如 a=1
的写法给出,不再接受通过位置隐式地捕获。
具体的做法是用一个单独的星号 *
参数,表示其后面的参数全部必须以 Keyword Arguments 形式提供。
举个例子:
>>> def f(*, a): # 声明 a 必须以 Keyword Arguments 形式提供
... print(a)
...
>>> f(1) # 尝试通过位置隐式提供,被抛出异常
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: f() takes 0 positional arguments but 1 was given
>>>
>>> f(a=1) # 通过 Keyword Arguments 形式显式地提供
1
>>>
初衷
在 这一节 中提到,Python 2.x 的时代,(*a, b)
这么定义函数是不合法的:
因为前面的 *a
会收集它后面的所有位置参数,如果存在一个 b
, 一定会被收集到 *a
中。
但是有这么一种场景需要(*a, b)
的写法:*a
是一系列主要参数,而 b
是一些辅助的、可选的、不那么重要的参数,可以不作为 位置参数 提供,而是作为 关键字参数 提供。
既然 *a
只收集位置参数,那么将 b
作为 关键字参数 提供,并不会引发歧义。
这就是 仅限关键字参数 Keyword-Only Arguments 的初衷。
例子
内置函数 max()
就是个很好的例子,定义如下:
max(arg1, arg2, *args[, key])
前面所有的 args
是参与比较的数值或者其他变量,而最后一个可选参数 key
以关键字参数的形式提供函数对象。
举个例子:
>>> max(1,2,3,4,5)
5
>>> max(1,2,3,4,5,key=lambda x:-x)
1
>>>
这个 key
参数是可选的、补充的。与此类似的还有 print()
>>> print('a', 'b', 'c', 'd', sep='|')
a|b|c|d
>>>
实现
为了实现这一需求,需要对 Python 2.x 的语法做出改变。
第1步改变
首先要做的是:允许 f(*a, b)
这种参数形式。下面的例子展示了两个版本不同的反应。
Python 2.x
# Python 2.x
>>> def f(*a, b):
File "<stdin>", line 1
def f(*a, b):
^
SyntaxError: invalid syntax
>>>
Python 3.x
# Python 3.x
>>> def f(*a, b):
... pass
...
>>>
可见在 Python2中不接受这种形式,而Python 3.x则允许了,允许的前提是,后面的参数必须以关键字形式提供:也就是类似 f(b=1)
这种形式,而不能仅仅提供一个数值,即 f(1)
这种形式是不接受的。
为什么能支持关键字参数,这里有一个隐含的逻辑是:f(*a, b)
参数列表中,*a
负责收集所有的 位置参数,而且是贪婪的行为,即尽可能多的收集位置参数,直到碰到第一个例外为止。如果这里碰到一个关键字参数,那么自然 *a
停止收集,就为后面的关键字参数的存在提供了可能性。
仅限关键字参数(Keyword-Only Arguments)是对调用者(也就是函数 arguments)的要求,而非对设计者(也就是 parameter)的要求。 具体说来,在声明函数的时候,没有必要为了显示关键字参数,而给出默认值;但是在使用函数的时候,必须以关键字参数的形式提供数值,而非位置参数。
第2步改变
第2步改变是在 第1步 基础上,进一步对语法的放宽。
现在已经允许这种写法:f(*a, b)
,但是有一种场景:关键字参数 b
前面没有 *a
这种 可变长度位置参数 的需求,而是一些固定的位置参数。除此之外,仅仅想规定后面的 b
为仅限关键字参数(Keyword-Only Arguments)。
下面举个例子:
def add(left, right, key):
...
这个二元加法函数明确的只接受两个操作数,而第三个参数 key
则希望规定为仅限关键字参数(Keyword-Only Arguments)。例如:
# 不接受
add('a', 'bc', len)
# 仅接受
add('a', 'bc', key=len)
key 前面没有了类似 *a
这样的可变长度参数引导。需要设计一种新语法标记后方的参数为仅限关键字参数(Keyword-Only Arguments)。仁慈的终生独裁者(BDFL):Guido van Rossum 决定使用单个星号作为位置参数的结束标志。
上面的函数声明应该写作:
def add(left, right, *, key):
...
如果您对本文有疑问或者寻求合作,欢迎 联系邮箱 。邮箱已到剪贴板
精彩评论
参考资料
本站 是个人网站,采用 署名协议 CC-BY-NC 授权。
欢迎转载,请保留原文链接 https://www.lfhacks.com/tech/python-keyword-only-arguments/ ,且不得用于商业用途。