使用关键字参数来提供可选行为


关键字参数

和其他的许多编程语言一样,调用Python中的函数可以根据参数的位置来指定传递的参数。

def remiander(number, divisor):
    return number % divisor

assert remainder(20, 7) == 6

Python函数中的所有的位置参数也可以通过关键字来传值,具体的使用方式就是在函数调用的时候使用类似于赋值的语句来指定参数名称。只要函数中的必须传值的参数被赋予了值,其他的参数的位置可以是随意次序的。你可以像玩“连连看”游戏似得来关联关键字位置参数。说起来可能不是那么容易理解,看一下具体的代码就会很简单了。下面的几种形式其实是等价的:

remainder(20, 7)
remainder(20, divisor=7)
remainder(number=20, divisor=7)
remainder(divisor=7, numer=20)

两个注意

  • 但是咧,位置参数应该先于关键字参数被指定。也就是说没有指定关键字的话,就会按顺序为函数传递参数值。
remainder(number=20, 7)
>>>
SyntaxError: non-keyword arg after keyword arg
  • 每个参数只能被赋值一次
remainder(20, number=7)
>>>
TypeError: remiander() got multiple values for argument 'number'

三大好处

关键字参数的灵活性给我们的程序带来了三个好处。

  • 第一个是代码可读性的提高,简单的使用remainder(20, 7)对程序调用者而言很不明显,到底哪个数字代表除数,哪个代表被除数呢?但是在关键字参数的调用实例中,一切都是那么的一目了然,特明显。
  • 第二个好处就是关键字参数可以在定义的时候初始化一个默认值。这就为你的程序提供了一个很好的拓展功能,尤其是大部分时间你只需要默认的行为的时候。这可以在一定程度上消除重复代码,减少代码干扰。 例如:你想计算液体流入一个桶中的速率。如果桶也有刻度的话,然后你就可以利用不同时间下的重量差来计算出流速了。
def flow_rate(weight_diff, time_diff):
     return weight_diff / time_diff

weight_diff = 0.5
time_diff = 3
rate = flow_date(weight_diff, time_diff)
print('%.3f kg per second' % flow)

在典型的案例中,每秒的千克流速是很有用的。其余时间,使用传感器测量大概的刻度就可以了,比如小时,天等等。你可以 在函数中添加一个period的参数来指定这一个行为。

def flow_rate(weight_diff, time_diff, period):
    return (weight_diff / time_diff) * period

但是问题也接踵而来了,每次调用此函数你你都必须指定period的大小,甚至是普通的情况(通常period是1)下也得这样。为了减少这种代码上的冗余,我们就可以使用带有默认值的关键字参数咯。

def flow_rate(weight_diff, time_diff, period=1):
    return (weight_diff / time_diff) * period

# 现在period参数也是可选的了,默认值为1
flow_per_second = flow_rate(weight_diff, time_diff)
flow_per_hour = flow_rate(weight_diff, time_diff, period=3600)

对于简单的默认值而言,这个函数可以很好的运行(当默认值很复杂的时候就会变得让人很为难,详见第20项:使用None和文档来指定动态的默认值参数)。

  • 第三个好处就是: 在前面的调用方式不变的情况下可以很好的拓展函数的参数。不用修改太多的代码,并且减少bug出现的机会。

    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,这样可以保证返回的重量仍然为千克。而对于之前的函数调用方而言,函数貌似并没有发生什么变化,照常调用即可,而新的函数调用方也可以指定新的关键字参数来查看新的行为了。这就是好的兼容项代码的最佳体现。

    pounds_per_hour = flow_rate(weight_diff, time_diff, period=3600, units_per_kg=2.2)
    

    大致来说,这个函数已经完美了。唯一遗憾的就是对于periodunits_per_kg来说仍然需要项位置参数一样被指定。

    pounds_per_hour = flow_rate(weight_diff, time_diff, 3600, 2.2)
    

    提供可选的位置参数可能会让你感到疑惑,因为36002.2到底是为哪个参数赋值不是很明显。这里我的建议就是,尽量的使用关键字参数来为它们赋值,而不要走使用位置参数来赋值的老路。

使用可选参数做到向后兼容对于程序的移植性很重要。


备忘录

  • 函数的参数值即可以通过位置被指定,也可以通过关键字来指定。
  • 相较于使用位置参数赋值,使用关键字来赋值会让你的赋值语句逻辑变得更加的清晰。
  • 带有默认参数的关键字参数函数可以很容易的添加新的行为,尤其适合向后兼容。
  • 可选的关键字参数应该优于位置参数被考虑使用。

results matching ""

    No results matching ""