30.3.5. 用关键字参数来表示可选的行为

与大多数其他编程语言一样,Python允许在调用函数时,按照位置传递参数。

def remainder(num, divisor):
    return num % divisor


assert remainder(20, 7)

Python函数里面的所有普通参数,除了按位置传递外,还可以按关键字传递。

调用函数时,在调用括号内可以把关键字的名称写在=左边,把参数值写在右边。

这种写法不在乎参数的顺序,只要把必须指定的所有位置参数全都传过去即可。

另外,关键字形式与位置形式也可以混用。下面这四种写法的效果相同:

def remainder(num, divisor):
    return num % divisor


assert remainder(20, 7) == 6

print(remainder(20, 7))
print(remainder(20, divisor=7))
print(remainder(num=20, divisor=7))
print(remainder(divisor=7, num=20))

如果混用,那么位置参数必须出现在关键字参数之前,否则就会出错。

每个参数只能指定一次,不能既通过位置形式指定,又通过关键字形式指定。

print(remainder(num=20,7))
print(20, num=7)

如果有一份字典,而且字典里面的内容能够用来调用remainder这样的函数,那么可以把**运算符加在字典前面,这会让Python把字典里面的键值以关键字参数的形式传给函数。

my_keys = {
    'num': 20,
    'divisor': 7
}
# print(remainder(**my_keys))
assert remainder(**my_keys) == 6

my_keys = {
    "divisor": 7
}
assert remainder(num=20, **my_keys)

也可以对多个字典分别施加**操作,只要这些字典所提供的参数不重叠就好

my_kwargs = {
    "num": 20,
}
other_kwargs = {
    "divisor": 7,
}

assert remainder(**my_kwargs, **other_kwargs) == 6

定义函数时,如果想让这个函数接受任意数量的关键字参数,那么可以在参数列表里写上万能形参**kwargs,它会把调用者传进来的参数收集合到一个字典里面稍后处理。

def print_parameters(**kwargs):
    for key, value in kwargs.items():
        print(f"{key}={value}")

print_parameters(alpha=1.5, beta=9, gamma=4)

关键字参数的灵活用法可以带来三个好处。

第一个好处是,用关键字参数调用函数可以让初次阅读代码的人更容易看懂。

第二个好处是,它可以带有默认值,该值是在定义函数时指定的。在大多数情况下,调用者只需要沿用这个值就好,但有时也可以明确指定自己想要传的值。这样能够减少重复代码,让程序看上去干净一些。

第三个好处是,我们可以很灵活地扩充函数的参数,而不用担心会影响原有的函数调用代码。

要点:

函数的参数可以按位置指定,也可以用关键字的形式指定。

关键字可以让每个参数的作用更加明了,因为在调用函数时只按位置指定参数,可能导致这些参数的含义不够明确。

应该通过带默认值的关键字参数来扩展函数的行为,因为这不会影响原有的函数调用代码。

可选的关键字参数总是应该通过参数名来传递,而不应按位置传递。