5

Python 的 Keyword-Only Arguments 理解

 2 years ago
source link: https://www.lfhacks.com/tech/python-keyword-only-arguments/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Python 的 Keyword-Only Arguments 理解

发布日期 2022-01-05
最后修改 2022-01-07
阅读 3 分钟
阅读量 167

扫一扫,转发文章

PEP-3102 建议了 Keyword-Only Arguments,并且在 Python3 中实现。本文试着在 Python 函数参数的基本理解 基础上,更深入的理解 Keyword-Only Arguments.

位置参数关键字参数 中我们看到,普通情形下,一个参数既可以通过位置捕获,也可以直接用名称捕获。

举个例子:

>>> def f(a):...     print(a)...>>> f(1)1>>> f(a=1)1>>>

Keyword-Only Arguments,意思是这种参数只能通过形如 a=1 的写法给出,不再接受通过位置隐式的捕获。

举个例子:

>>> def f(*, a):...     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)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):    ...
  1. https://www.python.org/dev/peps/pep-3102/

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK