特殊参数
默认情况下,参数可以按位置或显式关键字传递给 Python 函数。为了让代码易读、高效,最好限制参数的传递方式,这样,开发者只需查看函数定义,即可确定参数项是仅按位置、按位置或关键字,还是仅按关键字传递。
函数定义如下:
def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):
----------- ---------- ----------
| | |
| Positional or keyword |
| - Keyword only
-- Positional only
/ 和 * 是可选的。这些符号表明形参如何把参数值传递给函数:位置、位置或关键字、关键字。关键字形参也叫作命名形参。
位置或关键字参数
函数定义中未使用 / 和 * 时,参数可以按位置或关键字传递给函数。
仅位置参数
此处再介绍一些细节,特定形参可以标记为 仅限位置。仅限位置 时,形参的顺序很重要,且这些形参不能用关键字传递。仅限位置形参应放在 / (正斜杠)前。/ 用于在逻辑上分割仅限位置形参与其它形参。如果函数定义中没有 /,则表示没有仅限位置形参。
/ 后可以是 位置或关键字 或 仅限关键字 形参。
仅限关键字参数
把形参标记为 仅限关键字,表明必须以关键字参数形式传递该形参,应在参数列表中第一个 仅限关键字 形参前添加 *。
函数示例
请看下面的函数定义示例,注意 / 和 * 标记:
>>>
def standard_arg(arg):
print(arg)
def pos_only_arg(arg, /):
print(arg)
def kwd_only_arg(*, arg):
print(arg)
def combined_example(pos_only, /, standard, *, kwd_only):
print(pos_only, standard, kwd_only)
第一个函数定义 standard_arg 是最常见的形式,对调用方式没有任何限制,可以按位置也可以按关键字传递参数:
>>>
standard_arg(2)
2
standard_arg(arg=2)
2
第二个函数 pos_only_arg 的函数定义中有 /,仅限使用位置形参:
>>>
pos_only_arg(1)
1
pos_only_arg(arg=1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: pos_only_arg() got some positional-only arguments passed as keyword arguments: 'arg'
第三个函数 kwd_only_args 的函数定义通过 * 表明仅限关键字参数:
>>>
kwd_only_arg(3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: kwd_only_arg() takes 0 positional arguments but 1 was given
kwd_only_arg(arg=3)
3
最后一个函数在同一个函数定义中,使用了全部三种调用惯例:
>>>
combined_example(1, 2, 3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: combined_example() takes 2 positional arguments but 3 were given
combined_example(1, 2, kwd_only=3)
1 2 3
combined_example(1, standard=2, kwd_only=3)
1 2 3
combined_example(pos_only=1, standard=2, kwd_only=3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: combined_example() got some positional-only arguments passed as keyword arguments: 'pos_only'
下面的函数定义中,kwds 把 name 当作键,因此,可能与位置参数 name 产生潜在冲突:
def foo(name, **kwds):
return 'name' in kwds
调用该函数不可能返回 True,因为关键字 'name' 总与第一个形参绑定。例如:
>>>
foo(1, **{'name': 2})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: foo() got multiple values for argument 'name'
加上 / (仅限位置参数)后,就可以了。此时,函数定义把 name 当作位置参数,'name' 也可以作为关键字参数的键:
>>>
def foo(name, /, **kwds):
return 'name' in kwds
foo(1, **{'name': 2})
True
换句话说,仅限位置形参的名称可以在 **kwds 中使用,而不产生歧义。
小结
以下用例决定哪些形参可以用于函数定义:
def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):
说明:
使用仅限位置形参,可以让用户无法使用形参名。形参名没有实际意义时,强制调用函数的实参顺序时,或同时接收位置形参和关键字时,这种方式很有用。
当形参名有实际意义,且显式名称可以让函数定义更易理解时,阻止用户依赖传递实参的位置时,才使用关键字。
对于 API,使用仅限位置形参,可以防止未来修改形参名时造成破坏性的 API 变动。
|