与其他编程语言一样,调用python函数时,可以按位置传递参数。
def remainder(number, divisor):
return number % divisor
assert remainder(20,7) ==6
python中所有的位置参数,都可以按关键字传递。关键字参数的顺序不限,但位置参数必须在关键字参数之前。
remainder(20,divisor = 7)
remainder(number =20,divisor=7)
remainder(divisor=7,number=20)
上面这些调用都是等效的。但是下面这个会报错:
remainder(divisor=7,20)
>>>
SyntaxError: positional argument follows keyword argument
另外要注意的是每个参数只能指定一次。
remainder(20,number = 7)
>>>
TypeError: remainder() got multiple values for argument 'number'
灵活使用关键字参数,能带来三个重要的好处。
首先,以关键字参数来调用函数,能使读到这行代码的人更容易理解其含义。如果读到了remainder(20,7)这样的调用代码,那么必须 查看方法的实现代码,才能够明白这两个参数里面,究竟哪一个是被除数,哪一个是除数。若是改用关键字的形式来调用 ,则立刻就能根据number=20和divisor=7等写法来获知每个参数的含义。
关键字参数的第二个好处是,它可以在函数定义中提供默认值。在大部分情况下,函数调用者只需使用这些默认值就够了,若要开启某些附加功能,则可以指定相应的关键字参数。这样可以消除重复代码,并使代码变得整洁。
例如,要计算液体流入容器的速率。如果容器比较大,那么可以根据两个时间点上的重量差及时间差来判断流率。
def flow_rate(weight_diff, time_diff):
return weight_diff/time_diff
weight_diff = 0.5
time_diff = 3
flow = flow_rate(weight_diff, time_diff)
print('%.3f kg per second'%flow)
>>>
0.167 kg per second
通常情况下,求出每秒中流过的千克数就可以了。然而某些时候,可能想根据传感器上一次的读数,在更大的时间跨度上面估算流率,如以小时或天来估算。只需给函数添加一个参数,用来表示两种时间段的比例因子 ,即可提供这种行为。
def flow_rate(weight_diff, time_diff, period):
return (weight_diff/time_diff) *period
这样写的缺点是,每次调用函数时,都要指定period参数,即便我们想计算最常见的每秒流率,也依然要把1传给period参数。
flow_per_second = flow_rate(weight_diff, time_diff, 1)
为了使函数调用语句可能写得简单一些,我们可以给period参数定义默认值。
def flow_rate(weight_diff, time_diff, period=1):
return (weight_diff/time_diff) *period
现在的period 参数,就成了可选参数。
flow_per_second = flow_rate(weight_diff, time_diff)
flow_per_hour = flow_rate(weight_diff, time_diff, period=3600)
这种办法适用于比较简单的默认值。如果默认值比较复杂,这样写就不太好了,那种情况可以参考本书第20条。
使用关键字参数的第三个好处,是可以提供一种扩充函数参数的有效方式,使得扩充之后的函数依然能与原有的那些调用代码相兼容。我们不需要迁移大量代码,即可给函数添加新的功能,这减少了引入bug的概率。
例如,要扩充上述的flow_rate函数,使它能够根据千克之外的其他重量单位来计算流率。为此我们添加一个可选的参数,用以表示千克与那种重量单位之间的换算关系。
def flow_rate(weight_diff, time_diff, period=1, units_per_kg=1):
return ((weight_diff * units_per_kg) / time_diff) * period
units_per_kg参数的默认值是1,也就是说,如果该参数取默认值,那么 flow_rate 函数仍会以千克为重量单位来进行计算。这可以保证原来编写的那些函数调用代码,其行为都保持不变。而现在调用flow_rate的人,则可以通过这个新的关键字参数来使用该函数的新功能。
pounds_per_hour = flow_rate(weight_diff, time_diff, period=3600, units_per_kg=2.2)
这种写法只有一个缺陷,那就是period和units_per_kg 这种可选的关键字参数,仍然可以通过位置参数的形式来指定。
pounds_per_hour = flow_rate(weight_diff, time_diff, 3600, 2.2)
以位置参数的形式来指定可选参数,是容易令人困惑的,因为3600和2.2这样的值,其含义不清晰。最好的办法,是一直以关键字的形式来指定这些参数,而决不采用位置参数来指定它们。
要点:
- 函数参数可以按位置或关键字来指定。
- 只使用位置参数来调用函数,可能会导致这些参数值的含义不够明确,而关键字参数则能够阐明每个参数的意图。
- 给函数添加新的行为时,可以使用带默认值的关键字参数,以便与原有的函数调用代码保持兼容。
- 可行的关键字参数,总是应该以关键字形式来指定,而不应该以位置参数的形式来指定。